@scalar/components 0.27.7 → 0.27.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.
- package/README.md +2 -3
- package/dist/components/ScalarCodeBlock/ScalarCodeBlock.vue.d.ts.map +1 -1
- package/dist/components/ScalarCodeBlock/ScalarCodeBlock.vue.js.map +1 -1
- package/dist/components/ScalarCodeBlock/ScalarCodeBlock.vue.script.js +1 -1
- package/dist/components/ScalarCodeBlock/ScalarCodeBlock.vue.script.js.map +1 -1
- package/dist/components/ScalarMarkdown/ScalarMarkdown.vue.js.map +1 -1
- package/dist/components/ScalarMarkdown/ScalarMarkdown.vue.script.js.map +1 -1
- package/dist/components/ScalarTextArea/ScalarTextArea.vue.d.ts.map +1 -1
- package/dist/components/ScalarTextArea/ScalarTextArea.vue.js.map +1 -1
- package/dist/components/ScalarTextArea/ScalarTextArea.vue.script.js +1 -1
- package/dist/components/ScalarTextArea/ScalarTextArea.vue.script.js.map +1 -1
- package/dist/components/ScalarVirtualText/ScalarVirtualText.vue.js +1 -1
- package/dist/components/ScalarVirtualText/ScalarVirtualText.vue.js.map +1 -1
- package/dist/components/ScalarVirtualText/ScalarVirtualText.vue.script.js.map +1 -1
- package/dist/style.css +45 -23
- package/dist/vue-styles.css +13 -13
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -18,9 +18,8 @@ Scalar Components provides a library of components used across Scalar products.
|
|
|
18
18
|
Scalar is an open-source API platform for teams who want beautiful developer interfaces without vendor lock-in.
|
|
19
19
|
|
|
20
20
|
- **[API References](https://scalar.com/products/api-references/getting-started)** — Interactive API documentation from OpenAPI and AsyncAPI specs.
|
|
21
|
-
- **[Docs](https://scalar.com/products/docs/getting-started)** — Write in Markdown/MDX, generate API references, sync with two-way Git.
|
|
22
|
-
- **[
|
|
23
|
-
- **[MCP Servers](https://scalar.com/products/agent/getting-started)** — Generate secure MCP servers from your API spec.
|
|
21
|
+
- **[Developer Docs](https://scalar.com/products/docs/getting-started)** — Write in Markdown/MDX, generate API references, sync with two-way Git.
|
|
22
|
+
- **[SDK Generator](https://scalar.com/products/sdks/getting-started)** — Type-safe SDKs and CLIs in TypeScript, Python, Go, PHP, Java, and Ruby.
|
|
24
23
|
- **[API Client](https://scalar.com/products/api-client/getting-started)** — Open-source, offline-first Postman alternative built on OpenAPI.
|
|
25
24
|
|
|
26
25
|
20M+ monthly npm installs · 15,500+ GitHub stars · MIT licensed · [scalar.com](https://scalar.com)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarCodeBlock.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarCodeBlock/ScalarCodeBlock.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScalarCodeBlock.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarCodeBlock/ScalarCodeBlock.vue"],"names":[],"mappings":"AAwKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAGlD;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;cAEN,MAAM,GAAG,MAAM;2BACF,MAAM;WACtB,mBAAmB,GAAG,MAAM;kBACrB,OAAO;sBACH,MAAM,GAAG,MAAM,EAAE;WAC5B,QAAQ,GAAG,OAAO,GAAG,KAAK;;IAWzB,+CAA+C;aACtC,MAAM,GAAG,MAAM;;cAjBtB,MAAM,GAAG,MAAM;2BACF,MAAM;WACtB,mBAAmB,GAAG,MAAM;kBACrB,OAAO;sBACH,MAAM,GAAG,MAAM,EAAE;WAC5B,QAAQ,GAAG,OAAO,GAAG,KAAK;;IAezB;;;;OAIG;0BACmB,MAAM;;cAzB1B,MAAM,GAAG,MAAM;2BACF,MAAM;WACtB,mBAAmB,GAAG,MAAM;kBACrB,OAAO;sBACH,MAAM,GAAG,MAAM,EAAE;WAC5B,QAAQ,GAAG,OAAO,GAAG,KAAK;;IAWzB,+CAA+C;aACtC,MAAM,GAAG,MAAM;;cAjBtB,MAAM,GAAG,MAAM;2BACF,MAAM;WACtB,mBAAmB,GAAG,MAAM;kBACrB,OAAO;sBACH,MAAM,GAAG,MAAM,EAAE;WAC5B,QAAQ,GAAG,OAAO,GAAG,KAAK;;IAezB;;;;OAIG;0BACmB,MAAM;kGA4KlC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarCodeBlock.vue.js","names":[],"sources":["../../../src/components/ScalarCodeBlock/ScalarCodeBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Code Block component\n *\n * Renders syntax-highlighted code using highlight.js.\n * Supports line numbers, credential masking, and an optional copy button.\n *\n * @example\n * <ScalarCodeBlock content=\"const x = 1\" lang=\"javascript\" />\n */\nexport default {}\n</script>\n<script lang=\"ts\" setup>\nimport ScalarCopyBackdrop from '@/components/ScalarCopy/ScalarCopyBackdrop.vue'\nimport { standardLanguages, syntaxHighlight } from '@scalar/code-highlight'\nimport { prettyPrintJson } from '@scalar/helpers/json/pretty-print-json'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useId } from 'vue'\n\nimport { ScalarCodeBlockCopy } from '../ScalarCodeBlock'\nimport type { StandardLanguageKey } from './types'\n\ntype BaseProps = {\n content?: string | object\n prettyPrintedContent?: string\n lang?: StandardLanguageKey | string\n lineNumbers?: boolean\n hideCredentials?: string | string[]\n copy?: 'always' | 'hover' | false\n}\n\n/**\n * Uses highlight.js for syntax highlighting\n *\n * Requires at least one of content or prettyPrintedContent\n */\nconst {\n lang = 'plaintext',\n lineNumbers = false,\n copy = 'hover',\n content,\n prettyPrintedContent,\n hideCredentials,\n} = defineProps<\n BaseProps &\n (\n | {\n /** Raw unformatted object or string content */\n content: string | object\n }\n | {\n /**\n * Pre-pretty printed content string for better performance\n *\n * Avoids unnecessary costly re-serialization of large content\n */\n prettyPrintedContent: string\n }\n )\n>()\n\n/** Base id for the code block */\nconst id = useId()\n\n/** Formatted the content into an indented json string */\nconst prettyContent = computed(\n () => prettyPrintedContent || prettyPrintJson(content ?? ''),\n)\n\nconst highlightedCode = computed(() => {\n const html = syntaxHighlight(prettyContent.value, {\n lang: lang.trim(),\n languages: standardLanguages,\n lineNumbers: lineNumbers,\n maskCredentials: hideCredentials,\n })\n\n // Need to remove the wrapping <pre> element so we can use v-html without another wrapper\n return html.slice(5, -6)\n})\n\n/** Determine if the content is a single line */\nconst isOneLine = computed(() => !prettyContent.value.includes('\\n'))\n\nconst isContentValid = computed(() => {\n return (\n prettyContent.value !== null &&\n prettyContent.value !== 'null' &&\n prettyContent.value !== '404 Not Found'\n )\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx(\n 'scalar-code-block group/code-block flex flex-col',\n 'relative bg-b-1 min-h-0 min-w-0 focus-visible:outline',\n )\n \">\n <div\n tabindex=\"0\"\n class=\"custom-scroll overflow-x-auto p-2 -outline-offset-2 min-h-0 min-w-0 flex-1\">\n <pre\n :id=\"id\"\n class=\"m-0 bg-transparent text-nowrap whitespace-pre w-fit\"\n v-html=\"highlightedCode\" />\n </div>\n <ScalarCodeBlockCopy\n v-if=\"copy && isContentValid\"\n class=\"scalar-code-copy absolute\"\n :class=\"[\n isOneLine\n ? 'top-1/2 -translate-y-1/2 m-0 right-1'\n : 'top-2.5 right-2.5',\n { 'opacity-100': copy === 'always' },\n ]\"\n :content=\"prettyContent\"\n :showLang=\"!isOneLine\"\n :lang=\"lang\"\n :aria-controls=\"id\">\n <template #backdrop>\n <ScalarCopyBackdrop\n class=\"scalar-code-copy-backdrop\"\n :class=\"[\n isOneLine\n ? '-inset-y-0.75 -right-1 group-hocus-within/code-block:-left-0.5 left-3'\n : '-right-1.5 -top-1',\n ]\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n</template>\n<style>\n@reference '../../style.css';\n@import '@scalar/code-highlight/css/code.css';\n\n/** Disable font ligatures so code renders with literal characters */\n.scalar-code-block pre {\n font-variant-ligatures: none;\n}\n\n/** Make the copy button label backdrop match the background */\n.scalar-code-block.bg-b-1 .scalar-code-copy-backdrop {\n @apply bg-b-1;\n}\n.scalar-code-block.bg-b-2 .scalar-code-copy-backdrop {\n @apply bg-b-2;\n}\n/** Make the copy button one shade darker than the background */\n.scalar-code-block.bg-b-2 .scalar-code-copy {\n @apply bg-b-3;\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarCodeBlock.vue.js","names":[],"sources":["../../../src/components/ScalarCodeBlock/ScalarCodeBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Code Block component\n *\n * Renders syntax-highlighted code using highlight.js.\n * Supports line numbers, credential masking, and an optional copy button.\n *\n * @example\n * <ScalarCodeBlock content=\"const x = 1\" lang=\"javascript\" />\n */\nexport default {}\n</script>\n<script lang=\"ts\" setup>\nimport ScalarCopyBackdrop from '@/components/ScalarCopy/ScalarCopyBackdrop.vue'\nimport { standardLanguages, syntaxHighlight } from '@scalar/code-highlight'\nimport { prettyPrintJson } from '@scalar/helpers/json/pretty-print-json'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useId } from 'vue'\n\nimport { ScalarCodeBlockCopy } from '../ScalarCodeBlock'\nimport type { StandardLanguageKey } from './types'\n\ntype BaseProps = {\n content?: string | object\n prettyPrintedContent?: string\n lang?: StandardLanguageKey | string\n lineNumbers?: boolean\n hideCredentials?: string | string[]\n copy?: 'always' | 'hover' | false\n}\n\n/**\n * Uses highlight.js for syntax highlighting\n *\n * Requires at least one of content or prettyPrintedContent\n */\nconst {\n lang = 'plaintext',\n lineNumbers = false,\n copy = 'hover',\n content,\n prettyPrintedContent,\n hideCredentials,\n} = defineProps<\n BaseProps &\n (\n | {\n /** Raw unformatted object or string content */\n content: string | object\n }\n | {\n /**\n * Pre-pretty printed content string for better performance\n *\n * Avoids unnecessary costly re-serialization of large content\n */\n prettyPrintedContent: string\n }\n )\n>()\n\n/** Base id for the code block */\nconst id = useId()\n\n/** Formatted the content into an indented json string */\nconst prettyContent = computed(\n () => prettyPrintedContent || prettyPrintJson(content ?? ''),\n)\n\nconst highlightedCode = computed(() => {\n const html = syntaxHighlight(prettyContent.value, {\n lang: lang.trim(),\n languages: standardLanguages,\n lineNumbers: lineNumbers,\n maskCredentials: hideCredentials,\n })\n\n // Need to remove the wrapping <pre> element so we can use v-html without another wrapper\n return html.slice(5, -6)\n})\n\n/** Determine if the content is a single line */\nconst isOneLine = computed(() => !prettyContent.value.includes('\\n'))\n\nconst isContentValid = computed(() => {\n return (\n prettyContent.value !== null &&\n prettyContent.value !== 'null' &&\n prettyContent.value !== '404 Not Found'\n )\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx(\n 'scalar-code-block group/code-block flex flex-col',\n 'relative bg-b-1 min-h-0 min-w-0 focus-visible:outline',\n )\n \">\n <!-- Inherits the corners so the inset focus ring follows a rounded code block -->\n <div\n tabindex=\"0\"\n class=\"custom-scroll overflow-x-auto p-2 -outline-offset-2 rounded-[inherit] min-h-0 min-w-0 flex-1\">\n <pre\n :id=\"id\"\n class=\"m-0 bg-transparent text-nowrap whitespace-pre w-fit\"\n v-html=\"highlightedCode\" />\n </div>\n <ScalarCodeBlockCopy\n v-if=\"copy && isContentValid\"\n class=\"scalar-code-copy absolute\"\n :class=\"[\n isOneLine\n ? 'top-1/2 -translate-y-1/2 m-0 right-1'\n : 'top-2.5 right-2.5',\n { 'opacity-100': copy === 'always' },\n ]\"\n :content=\"prettyContent\"\n :showLang=\"!isOneLine\"\n :lang=\"lang\"\n :aria-controls=\"id\">\n <template #backdrop>\n <ScalarCopyBackdrop\n class=\"scalar-code-copy-backdrop\"\n :class=\"[\n isOneLine\n ? '-inset-y-0.75 -right-1 group-hocus-within/code-block:-left-0.5 left-3'\n : '-right-1.5 -top-1',\n ]\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n</template>\n<style>\n@reference '../../style.css';\n@import '@scalar/code-highlight/css/code.css';\n\n/** Disable font ligatures so code renders with literal characters */\n.scalar-code-block pre {\n font-variant-ligatures: none;\n}\n\n/** Make the copy button label backdrop match the background */\n.scalar-code-block.bg-b-1 .scalar-code-copy-backdrop {\n @apply bg-b-1;\n}\n.scalar-code-block.bg-b-2 .scalar-code-copy-backdrop {\n @apply bg-b-2;\n}\n/** Make the copy button one shade darker than the background */\n.scalar-code-block.bg-b-2 .scalar-code-copy {\n @apply bg-b-3;\n}\n</style>\n"],"mappings":""}
|
|
@@ -7,7 +7,7 @@ import { prettyPrintJson } from "@scalar/helpers/json/pretty-print-json";
|
|
|
7
7
|
//#region src/components/ScalarCodeBlock/ScalarCodeBlock.vue?vue&type=script&setup=true&lang.ts
|
|
8
8
|
var _hoisted_1 = {
|
|
9
9
|
tabindex: "0",
|
|
10
|
-
class: "custom-scroll overflow-x-auto p-2 -outline-offset-2 min-h-0 min-w-0 flex-1"
|
|
10
|
+
class: "custom-scroll overflow-x-auto p-2 -outline-offset-2 rounded-[inherit] min-h-0 min-w-0 flex-1"
|
|
11
11
|
};
|
|
12
12
|
var _hoisted_2 = ["id", "innerHTML"];
|
|
13
13
|
var ScalarCodeBlock_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarCodeBlock.vue.script.js","names":[],"sources":["../../../src/components/ScalarCodeBlock/ScalarCodeBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Code Block component\n *\n * Renders syntax-highlighted code using highlight.js.\n * Supports line numbers, credential masking, and an optional copy button.\n *\n * @example\n * <ScalarCodeBlock content=\"const x = 1\" lang=\"javascript\" />\n */\nexport default {}\n</script>\n<script lang=\"ts\" setup>\nimport ScalarCopyBackdrop from '@/components/ScalarCopy/ScalarCopyBackdrop.vue'\nimport { standardLanguages, syntaxHighlight } from '@scalar/code-highlight'\nimport { prettyPrintJson } from '@scalar/helpers/json/pretty-print-json'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useId } from 'vue'\n\nimport { ScalarCodeBlockCopy } from '../ScalarCodeBlock'\nimport type { StandardLanguageKey } from './types'\n\ntype BaseProps = {\n content?: string | object\n prettyPrintedContent?: string\n lang?: StandardLanguageKey | string\n lineNumbers?: boolean\n hideCredentials?: string | string[]\n copy?: 'always' | 'hover' | false\n}\n\n/**\n * Uses highlight.js for syntax highlighting\n *\n * Requires at least one of content or prettyPrintedContent\n */\nconst {\n lang = 'plaintext',\n lineNumbers = false,\n copy = 'hover',\n content,\n prettyPrintedContent,\n hideCredentials,\n} = defineProps<\n BaseProps &\n (\n | {\n /** Raw unformatted object or string content */\n content: string | object\n }\n | {\n /**\n * Pre-pretty printed content string for better performance\n *\n * Avoids unnecessary costly re-serialization of large content\n */\n prettyPrintedContent: string\n }\n )\n>()\n\n/** Base id for the code block */\nconst id = useId()\n\n/** Formatted the content into an indented json string */\nconst prettyContent = computed(\n () => prettyPrintedContent || prettyPrintJson(content ?? ''),\n)\n\nconst highlightedCode = computed(() => {\n const html = syntaxHighlight(prettyContent.value, {\n lang: lang.trim(),\n languages: standardLanguages,\n lineNumbers: lineNumbers,\n maskCredentials: hideCredentials,\n })\n\n // Need to remove the wrapping <pre> element so we can use v-html without another wrapper\n return html.slice(5, -6)\n})\n\n/** Determine if the content is a single line */\nconst isOneLine = computed(() => !prettyContent.value.includes('\\n'))\n\nconst isContentValid = computed(() => {\n return (\n prettyContent.value !== null &&\n prettyContent.value !== 'null' &&\n prettyContent.value !== '404 Not Found'\n )\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx(\n 'scalar-code-block group/code-block flex flex-col',\n 'relative bg-b-1 min-h-0 min-w-0 focus-visible:outline',\n )\n \">\n <div\n tabindex=\"0\"\n class=\"custom-scroll overflow-x-auto p-2 -outline-offset-2 min-h-0 min-w-0 flex-1\">\n <pre\n :id=\"id\"\n class=\"m-0 bg-transparent text-nowrap whitespace-pre w-fit\"\n v-html=\"highlightedCode\" />\n </div>\n <ScalarCodeBlockCopy\n v-if=\"copy && isContentValid\"\n class=\"scalar-code-copy absolute\"\n :class=\"[\n isOneLine\n ? 'top-1/2 -translate-y-1/2 m-0 right-1'\n : 'top-2.5 right-2.5',\n { 'opacity-100': copy === 'always' },\n ]\"\n :content=\"prettyContent\"\n :showLang=\"!isOneLine\"\n :lang=\"lang\"\n :aria-controls=\"id\">\n <template #backdrop>\n <ScalarCopyBackdrop\n class=\"scalar-code-copy-backdrop\"\n :class=\"[\n isOneLine\n ? '-inset-y-0.75 -right-1 group-hocus-within/code-block:-left-0.5 left-3'\n : '-right-1.5 -top-1',\n ]\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n</template>\n<style>\n@reference '../../style.css';\n@import '@scalar/code-highlight/css/code.css';\n\n/** Disable font ligatures so code renders with literal characters */\n.scalar-code-block pre {\n font-variant-ligatures: none;\n}\n\n/** Make the copy button label backdrop match the background */\n.scalar-code-block.bg-b-1 .scalar-code-copy-backdrop {\n @apply bg-b-1;\n}\n.scalar-code-block.bg-b-2 .scalar-code-copy-backdrop {\n @apply bg-b-2;\n}\n/** Make the copy button one shade darker than the background */\n.scalar-code-block.bg-b-2 .scalar-code-copy {\n @apply bg-b-3;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8DA,MAAM,KAAK,OAAM;;EAGjB,MAAM,gBAAgB,eACd,QAAA,wBAAwB,gBAAgB,QAAA,WAAW,GAAG,CAC9D;EAEA,MAAM,kBAAkB,eAAe;AASrC,UARa,gBAAgB,cAAc,OAAO;IAChD,MAAM,QAAA,KAAK,MAAM;IACjB,WAAW;IACX,aAAa,QAAA;IACb,iBAAiB,QAAA;IAClB,CAAA,CAGW,MAAM,GAAG,GAAE;IACxB;;EAGD,MAAM,YAAY,eAAe,CAAC,cAAc,MAAM,SAAS,KAAK,CAAA;EAEpE,MAAM,iBAAiB,eAAe;AACpC,UACE,cAAc,UAAU,QACxB,cAAc,UAAU,UACxB,cAAc,UAAU;IAE3B;EAGD,MAAM,EAAE,OAAO,WAAU;;uBAGvB,
|
|
1
|
+
{"version":3,"file":"ScalarCodeBlock.vue.script.js","names":[],"sources":["../../../src/components/ScalarCodeBlock/ScalarCodeBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Code Block component\n *\n * Renders syntax-highlighted code using highlight.js.\n * Supports line numbers, credential masking, and an optional copy button.\n *\n * @example\n * <ScalarCodeBlock content=\"const x = 1\" lang=\"javascript\" />\n */\nexport default {}\n</script>\n<script lang=\"ts\" setup>\nimport ScalarCopyBackdrop from '@/components/ScalarCopy/ScalarCopyBackdrop.vue'\nimport { standardLanguages, syntaxHighlight } from '@scalar/code-highlight'\nimport { prettyPrintJson } from '@scalar/helpers/json/pretty-print-json'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useId } from 'vue'\n\nimport { ScalarCodeBlockCopy } from '../ScalarCodeBlock'\nimport type { StandardLanguageKey } from './types'\n\ntype BaseProps = {\n content?: string | object\n prettyPrintedContent?: string\n lang?: StandardLanguageKey | string\n lineNumbers?: boolean\n hideCredentials?: string | string[]\n copy?: 'always' | 'hover' | false\n}\n\n/**\n * Uses highlight.js for syntax highlighting\n *\n * Requires at least one of content or prettyPrintedContent\n */\nconst {\n lang = 'plaintext',\n lineNumbers = false,\n copy = 'hover',\n content,\n prettyPrintedContent,\n hideCredentials,\n} = defineProps<\n BaseProps &\n (\n | {\n /** Raw unformatted object or string content */\n content: string | object\n }\n | {\n /**\n * Pre-pretty printed content string for better performance\n *\n * Avoids unnecessary costly re-serialization of large content\n */\n prettyPrintedContent: string\n }\n )\n>()\n\n/** Base id for the code block */\nconst id = useId()\n\n/** Formatted the content into an indented json string */\nconst prettyContent = computed(\n () => prettyPrintedContent || prettyPrintJson(content ?? ''),\n)\n\nconst highlightedCode = computed(() => {\n const html = syntaxHighlight(prettyContent.value, {\n lang: lang.trim(),\n languages: standardLanguages,\n lineNumbers: lineNumbers,\n maskCredentials: hideCredentials,\n })\n\n // Need to remove the wrapping <pre> element so we can use v-html without another wrapper\n return html.slice(5, -6)\n})\n\n/** Determine if the content is a single line */\nconst isOneLine = computed(() => !prettyContent.value.includes('\\n'))\n\nconst isContentValid = computed(() => {\n return (\n prettyContent.value !== null &&\n prettyContent.value !== 'null' &&\n prettyContent.value !== '404 Not Found'\n )\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx(\n 'scalar-code-block group/code-block flex flex-col',\n 'relative bg-b-1 min-h-0 min-w-0 focus-visible:outline',\n )\n \">\n <!-- Inherits the corners so the inset focus ring follows a rounded code block -->\n <div\n tabindex=\"0\"\n class=\"custom-scroll overflow-x-auto p-2 -outline-offset-2 rounded-[inherit] min-h-0 min-w-0 flex-1\">\n <pre\n :id=\"id\"\n class=\"m-0 bg-transparent text-nowrap whitespace-pre w-fit\"\n v-html=\"highlightedCode\" />\n </div>\n <ScalarCodeBlockCopy\n v-if=\"copy && isContentValid\"\n class=\"scalar-code-copy absolute\"\n :class=\"[\n isOneLine\n ? 'top-1/2 -translate-y-1/2 m-0 right-1'\n : 'top-2.5 right-2.5',\n { 'opacity-100': copy === 'always' },\n ]\"\n :content=\"prettyContent\"\n :showLang=\"!isOneLine\"\n :lang=\"lang\"\n :aria-controls=\"id\">\n <template #backdrop>\n <ScalarCopyBackdrop\n class=\"scalar-code-copy-backdrop\"\n :class=\"[\n isOneLine\n ? '-inset-y-0.75 -right-1 group-hocus-within/code-block:-left-0.5 left-3'\n : '-right-1.5 -top-1',\n ]\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n</template>\n<style>\n@reference '../../style.css';\n@import '@scalar/code-highlight/css/code.css';\n\n/** Disable font ligatures so code renders with literal characters */\n.scalar-code-block pre {\n font-variant-ligatures: none;\n}\n\n/** Make the copy button label backdrop match the background */\n.scalar-code-block.bg-b-1 .scalar-code-copy-backdrop {\n @apply bg-b-1;\n}\n.scalar-code-block.bg-b-2 .scalar-code-copy-backdrop {\n @apply bg-b-2;\n}\n/** Make the copy button one shade darker than the background */\n.scalar-code-block.bg-b-2 .scalar-code-copy {\n @apply bg-b-3;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8DA,MAAM,KAAK,OAAM;;EAGjB,MAAM,gBAAgB,eACd,QAAA,wBAAwB,gBAAgB,QAAA,WAAW,GAAG,CAC9D;EAEA,MAAM,kBAAkB,eAAe;AASrC,UARa,gBAAgB,cAAc,OAAO;IAChD,MAAM,QAAA,KAAK,MAAM;IACjB,WAAW;IACX,aAAa,QAAA;IACb,iBAAiB,QAAA;IAClB,CAAA,CAGW,MAAM,GAAG,GAAE;IACxB;;EAGD,MAAM,YAAY,eAAe,CAAC,cAAc,MAAM,SAAS,KAAK,CAAA;EAEpE,MAAM,iBAAiB,eAAe;AACpC,UACE,cAAc,UAAU,QACxB,cAAc,UAAU,UACxB,cAAc,UAAU;IAE3B;EAGD,MAAM,EAAE,OAAO,WAAU;;uBAGvB,mBAuCM,OAAA,eAAA,mBAtCW,MAAA,GAAE,CAAA,oDAAA,wDAAA,CAAA,CAAA,EAAA,CAOjB,mBAOM,OAPN,YAOM,CAJJ,mBAG6B,OAAA;IAF1B,IAAI,MAAA,GAAE;IACP,OAAM;IACN,WAAQ,gBAAA;8BAGJ,QAAA,QAAQ,eAAA,SAAA,WAAA,EADhB,YAsBsB,MAAA,4BAAA,EAAA;;IApBpB,OAAK,eAAA,CAAC,6BAA2B,CACf,UAAA,QAAA,yCAAA,qBAAA,EAAA,eAAuH,QAAA,SAAI,UAAA,CAAA,CAAA,CAAA;IAM5I,SAAS,cAAA;IACT,UAAQ,CAAG,UAAA;IACX,MAAM,QAAA;IACN,iBAAe,MAAA,GAAE;;IACP,UAAQ,cAOV,CANP,YAMO,4BAAA,EALL,OAAK,eAAA,CAAC,6BAA2B,CACX,UAAA,QAAA,0EAAA,oBAAA,CAAA,CAAA,EAAA,EAAA,MAAA,GAAA,CAAA,QAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarMarkdown.vue.js","names":[],"sources":["../../../src/components/ScalarMarkdown/ScalarMarkdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Markdown component\n *\n * Renders a markdown string as styled HTML with support for\n * headings, links, code blocks, tables, alerts, and more.\n *\n * @example\n * <ScalarMarkdown value=\"# Hello World\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n type Node,\n htmlFromMarkdown,\n isHeading,\n textFromNode,\n} from '@scalar/code-highlight'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useTemplateRef } from 'vue'\n\nimport type { ScalarMarkdownProps } from './types'\n\nconst {\n value,\n transform,\n transformType,\n withImages = false,\n withAnchors = false,\n anchorPrefix,\n} = defineProps<ScalarMarkdownProps>()\n\nconst { cx } = useBindCx()\ndefineOptions({ inheritAttrs: false })\n\n// Expose the element ref to the parent component\nconst templateRef = useTemplateRef('div')\ndefineExpose({ el: templateRef })\n\nconst transformHeading = (node: Node) => {\n if (!withAnchors) {\n return transform?.(node) || node\n }\n\n if (!isHeading(node)) {\n return node\n }\n\n const headingText = textFromNode(node)\n\n /** Basic slugify for the heading text */\n const slug = headingText.toLowerCase().replace(/\\s+/g, '-')\n\n /** Return adding anchor prefix if present or just the slug */\n const id = anchorPrefix ? `${anchorPrefix}/description/${slug}` : slug\n\n // Add the id to the heading\n node.data = {\n hProperties: {\n id,\n },\n }\n\n if (transform) {\n return transform(node)\n }\n\n return node\n}\n\nconst html = computed(() => {\n return htmlFromMarkdown(value ?? '', {\n removeTags: withImages ? [] : ['img', 'picture'],\n transform:\n withAnchors && transformType === 'heading' ? transformHeading : transform,\n transformType,\n })\n})\n</script>\n<template>\n <div\n ref=\"div\"\n v-bind=\"cx('markdown', { 'line-clamp-(--markdown-clamp)': !!clamp })\"\n :style=\"{ '--markdown-clamp': clamp }\"\n v-html=\"html\" />\n</template>\n<style>\n@import '@scalar/code-highlight/css/code.css';\n\n.scalar-app {\n /* Base container and variables */\n .markdown {\n --scalar-refs-heading-spacing: 24px;\n --markdown-border: var(--scalar-border-width) solid\n var(--scalar-border-color);\n --markdown-spacing-sm: 12px;\n --markdown-spacing-md: 16px;\n --markdown-line-height: 1.625;\n --markdown-heading-line-height: 1.15;\n\n font-family: var(--scalar-font);\n word-break: break-word;\n line-height: var(--markdown-line-height);\n }\n\n .markdown > * {\n margin-bottom: var(--markdown-spacing-md);\n }\n\n /* margin gets doubled between heading + non heading elements if we don't do this*/\n .markdown > *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):last-child {\n margin-bottom: 0;\n }\n /* Headings */\n .markdown h1,\n .markdown h2,\n .markdown h3,\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n display: block;\n font-weight: var(--scalar-bold);\n margin-top: var(--scalar-refs-heading-spacing);\n margin-bottom: var(--markdown-spacing-sm);\n line-height: var(--markdown-heading-line-height, 1.15);\n scroll-margin-top: 1rem;\n }\n .markdown h1 {\n font-size: 1.5rem;\n }\n .markdown h2,\n .markdown h3 {\n font-size: 1.25rem;\n }\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n font-size: 1rem;\n }\n\n /* Text formatting and paragraphs */\n .markdown b,\n .markdown strong {\n font-weight: var(--scalar-bold);\n }\n\n .markdown p {\n color: inherit;\n display: block;\n line-height: var(--markdown-line-height);\n }\n\n /* Images */\n .markdown img {\n /**\n * With `display: block` <a><img></a> will take the whole width.\n *\n * @see https://github.com/scalar/scalar/issues/3961\n */\n display: inline-block;\n overflow: hidden;\n border-radius: var(--scalar-radius);\n max-width: 100%;\n }\n\n /* Lists */\n .markdown ul,\n .markdown ol {\n display: flex;\n flex-direction: column;\n padding-left: 1.6em;\n gap: 2px;\n line-height: var(--markdown-line-height);\n }\n\n .markdown li {\n margin-top: 2px;\n padding-left: 7px;\n }\n\n ol > li::marker,\n ol > * > li::marker {\n font: var(--scalar-font);\n font-variant-numeric: tabular-nums;\n font-weight: var(--scalar-semibold);\n white-space: nowrap;\n }\n\n /* Level 1, 4, 7 → decimal */\n .markdown ol {\n list-style-type: decimal;\n }\n /* Level 2, 5, 8 → lower-alpha */\n .markdown ol ol {\n list-style-type: lower-alpha;\n }\n\n .markdown ol ol ol ol,\n .markdown ol ol ol ol ol ol ol {\n list-style-type: decimal;\n }\n\n .markdown ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol {\n list-style-type: lower-alpha;\n }\n\n /* Level 3, 6, 9 → lower-roman */\n .markdown ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ol ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ul > li,\n .markdown ul > * > li {\n list-style-type: disc;\n }\n\n /* Tables */\n .markdown table {\n display: table;\n table-layout: fixed;\n overflow-x: auto;\n position: relative;\n width: max-content;\n max-width: 100%;\n margin: 1em 0;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius);\n border-spacing: 0;\n }\n\n .markdown tbody,\n .markdown thead {\n vertical-align: middle;\n }\n\n .markdown tbody {\n display: table-row-group;\n }\n\n .markdown thead {\n display: table-header-group;\n }\n\n .markdown tr {\n display: table-row;\n border-color: inherit;\n vertical-align: inherit;\n }\n\n .markdown td,\n .markdown th {\n display: table-cell;\n vertical-align: top;\n min-width: 1em;\n padding: 8.5px 16px;\n line-height: var(--markdown-line-height);\n position: relative;\n /** Break long words in tables */\n word-break: break-word;\n font-size: var(--scalar-small);\n color: var(--scalar-color-1);\n border-right: var(--markdown-border);\n border-bottom: var(--markdown-border);\n }\n\n .markdown td > *,\n .markdown th > * {\n margin-bottom: 0;\n }\n\n .markdown th:empty {\n display: none;\n }\n\n .markdown td:first-of-type,\n .markdown th:first-of-type {\n border-left: none;\n }\n\n .markdown td:last-of-type,\n .markdown th:last-of-type {\n border-right: none;\n }\n\n .markdown tr:last-of-type td {\n border-bottom: none;\n }\n\n .markdown th {\n font-weight: var(--scalar-bold);\n text-align: left;\n border-left-color: transparent;\n background: var(--scalar-background-2);\n }\n\n .markdown th:first-of-type {\n border-top-left-radius: var(--scalar-radius);\n }\n\n .markdown th:last-of-type {\n border-top-right-radius: var(--scalar-radius);\n }\n\n .markdown tr > [align='left'] {\n text-align: left;\n }\n\n .markdown tr > [align='right'] {\n text-align: right;\n }\n\n .markdown tr > [align='center'] {\n text-align: center;\n }\n\n /* Details */\n .markdown details {\n border: var(--markdown-border);\n border-radius: var(--scalar-radius-xl);\n color: var(--scalar-color-1);\n }\n\n .markdown details > :not(summary) {\n margin: var(--markdown-spacing-md);\n margin-bottom: 0;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) {\n margin-bottom: 8px;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) + * {\n margin-top: 0;\n }\n\n .markdown details > table {\n width: calc(100% - calc(var(--markdown-spacing-md) * 2));\n }\n\n .markdown summary {\n border-radius: 2.5px;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-height: 40px;\n padding: 7px 14px;\n position: relative;\n font-weight: var(--scalar-semibold);\n line-height: var(--markdown-line-height);\n cursor: pointer;\n user-select: none;\n }\n\n .markdown summary:hover {\n background-color: var(--scalar-background-2);\n }\n\n .markdown details[open] {\n padding-bottom: var(--markdown-spacing-md);\n }\n\n .markdown details[open] > summary {\n border-bottom: var(--markdown-border);\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n .markdown summary::before {\n display: block;\n content: '';\n flex-shrink: 0;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n background-color: var(--scalar-color-3);\n mask-image: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" width=\"1em\" height=\"1em\"><path d=\"M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z\"></path></svg>');\n margin-top: 5px;\n }\n\n .markdown summary:hover::before {\n background-color: var(--scalar-color-1);\n }\n\n .markdown details[open] > summary::before {\n transform: rotate(90deg);\n transition: transform 0.1s ease-in-out;\n }\n\n .markdown details:has(+ details) {\n border-bottom: 0;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n margin-bottom: 0;\n }\n\n .markdown details:has(+ details) + details,\n .markdown details:has(+ details) + details > summary {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n\n /* Links */\n .markdown a {\n --font-color: var(--scalar-link-color, var(--scalar-color-accent));\n --font-visited: var(--scalar-link-color-visited, var(--scalar-color-2));\n text-decoration: var(--scalar-text-decoration);\n\n color: var(--font-color);\n font-weight: var(--scalar-link-font-weight, var(--scalar-semibold));\n text-underline-offset: 0.25rem;\n text-decoration-thickness: 1px;\n text-decoration-color: color-mix(\n in srgb,\n var(--font-color) 30%,\n transparent\n );\n }\n\n .markdown a:hover {\n text-decoration-color: var(--scalar-color-1, currentColor);\n color: var(--scalar-link-color-hover, var(--scalar-color-accent));\n -webkit-text-decoration: var(--scalar-text-decoration-hover);\n text-decoration: var(--scalar-text-decoration-hover);\n }\n\n .markdown a:visited {\n color: var(--font-visited);\n }\n\n /* Text effects and formatting */\n .markdown em {\n font-style: italic;\n }\n\n .markdown sup,\n .markdown sub {\n font-size: var(--scalar-micro);\n font-weight: 450;\n }\n\n .markdown sup {\n vertical-align: super;\n }\n\n .markdown sub {\n vertical-align: sub;\n }\n\n .markdown del {\n text-decoration: line-through;\n }\n\n /* Code blocks and inline code */\n .markdown code {\n font-family: var(--scalar-font-code);\n background-color: var(--scalar-background-2);\n box-shadow: 0 0 0 var(--scalar-border-width) var(--scalar-border-color);\n font-size: var(--scalar-micro);\n border-radius: 2px;\n padding: 0 3px;\n }\n\n .markdown .hljs {\n font-size: var(--scalar-small);\n }\n\n .markdown pre code {\n display: block;\n white-space: pre;\n padding: var(--markdown-spacing-sm);\n line-height: 1.5;\n margin: var(--markdown-spacing-sm) 0;\n -webkit-overflow-scrolling: touch;\n overflow-x: auto;\n max-width: 100%;\n min-width: 100px;\n }\n\n /* Horizontal rules */\n .markdown hr {\n border: none;\n border-bottom: var(--markdown-border);\n }\n\n /* Blockquotes */\n .markdown blockquote {\n border-left: 2px solid var(--scalar-border-color);\n padding-left: var(--markdown-spacing-sm);\n }\n\n .markdown blockquote > * {\n margin-bottom: var(--markdown-spacing-sm);\n }\n\n /* Markdown Checklist */\n .markdown li.task-list-item {\n position: relative;\n list-style: none;\n }\n\n .markdown li.task-list-item > input {\n display: inline;\n position: absolute;\n top: 0.225em;\n left: -1.4em;\n appearance: none;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n border: 1px solid var(--scalar-color-3);\n border-radius: var(--scalar-radius);\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked {\n background-color: var(--scalar-color-1);\n border-color: var(--scalar-color-1);\n }\n\n .markdown li.task-list-item > input[type='checkbox']::before {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 10px;\n border: solid var(--scalar-background-1);\n border-width: 0 1.5px 1.5px 0;\n transform: rotate(45deg);\n opacity: 0;\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked::before {\n opacity: 1;\n }\n\n /* Markdown Alert */\n .markdown .markdown-alert {\n align-items: stretch;\n border-radius: var(--scalar-radius);\n background-color: color-mix(\n in srgb,\n var(--scalar-background-2),\n transparent\n );\n border: var(--markdown-border);\n display: flex;\n gap: var(--markdown-spacing-sm);\n padding: 10px 14px;\n position: relative;\n }\n\n .markdown .markdown-alert .markdown-alert-icon::before {\n content: '';\n display: block;\n width: 18px;\n height: 18px;\n background-color: currentColor;\n flex-shrink: 0;\n margin-top: 3px;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n }\n\n .markdown .markdown-alert.markdown-alert-note {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-blue),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-blue), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-tip {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-2),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-2), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before,\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z\"></path></svg>');\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-important,\n .markdown .markdown-alert.markdown-alert-warning {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-orange),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-orange), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before,\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z\"></path></svg>');\n }\n\n .markdown .markdown-alert.markdown-alert-caution {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-red),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-red), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-caution\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z\"></path></svg>');\n color: var(--scalar-color-red);\n }\n\n .markdown .markdown-alert.markdown-alert-success {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-green),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-green), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-success\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z\"></path></svg>');\n color: var(--scalar-color-green);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before {\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n color: var(--scalar-color-2);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before {\n color: var(--scalar-color-purple);\n }\n\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n color: var(--scalar-color-orange);\n }\n\n .markdown .markdown-alert .markdown-alert-content {\n margin: 0;\n line-height: var(--markdown-line-height);\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarMarkdown.vue.js","names":[],"sources":["../../../src/components/ScalarMarkdown/ScalarMarkdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Markdown component\n *\n * Renders a markdown string as styled HTML with support for\n * headings, links, code blocks, tables, alerts, and more.\n *\n * @example\n * <ScalarMarkdown value=\"# Hello World\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n type Node,\n htmlFromMarkdown,\n isHeading,\n textFromNode,\n} from '@scalar/code-highlight'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useTemplateRef } from 'vue'\n\nimport type { ScalarMarkdownProps } from './types'\n\nconst {\n value,\n transform,\n transformType,\n withImages = false,\n withAnchors = false,\n anchorPrefix,\n} = defineProps<ScalarMarkdownProps>()\n\nconst { cx } = useBindCx()\ndefineOptions({ inheritAttrs: false })\n\n// Expose the element ref to the parent component\nconst templateRef = useTemplateRef('div')\ndefineExpose({ el: templateRef })\n\nconst transformHeading = (node: Node) => {\n if (!withAnchors) {\n return transform?.(node) || node\n }\n\n if (!isHeading(node)) {\n return node\n }\n\n const headingText = textFromNode(node)\n\n /** Basic slugify for the heading text */\n const slug = headingText.toLowerCase().replace(/\\s+/g, '-')\n\n /** Return adding anchor prefix if present or just the slug */\n const id = anchorPrefix ? `${anchorPrefix}/description/${slug}` : slug\n\n // Add the id to the heading\n node.data = {\n hProperties: {\n id,\n },\n }\n\n if (transform) {\n return transform(node)\n }\n\n return node\n}\n\nconst html = computed(() => {\n return htmlFromMarkdown(value ?? '', {\n removeTags: withImages ? [] : ['img', 'picture'],\n transform:\n withAnchors && transformType === 'heading' ? transformHeading : transform,\n transformType,\n })\n})\n</script>\n<template>\n <div\n ref=\"div\"\n v-bind=\"cx('markdown', { 'line-clamp-(--markdown-clamp)': !!clamp })\"\n :style=\"{ '--markdown-clamp': clamp }\"\n v-html=\"html\" />\n</template>\n<style>\n@import '@scalar/code-highlight/css/code.css';\n\n.scalar-app {\n /* Base container and variables */\n .markdown {\n --scalar-refs-heading-spacing: 24px;\n --markdown-border: var(--scalar-border-width) solid\n var(--scalar-border-color);\n --markdown-spacing-sm: 12px;\n --markdown-spacing-md: 16px;\n --markdown-line-height: 1.625;\n --markdown-heading-line-height: 1.15;\n\n font-family: var(--scalar-font);\n word-break: break-word;\n line-height: var(--markdown-line-height);\n }\n\n .markdown > * {\n margin-bottom: var(--markdown-spacing-md);\n }\n\n /* margin gets doubled between heading + non heading elements if we don't do this*/\n .markdown > *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):last-child {\n margin-bottom: 0;\n }\n /* Headings */\n .markdown h1,\n .markdown h2,\n .markdown h3,\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n display: block;\n font-weight: var(--scalar-bold);\n margin-top: var(--scalar-refs-heading-spacing);\n margin-bottom: var(--markdown-spacing-sm);\n line-height: var(--markdown-heading-line-height, 1.15);\n scroll-margin-top: 1rem;\n }\n .markdown h1 {\n font-size: 1.5rem;\n }\n .markdown h2,\n .markdown h3 {\n font-size: 1.25rem;\n }\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n font-size: 1rem;\n }\n\n /* Text formatting and paragraphs */\n .markdown b,\n .markdown strong {\n font-weight: var(--scalar-bold);\n }\n\n .markdown p {\n color: inherit;\n display: block;\n line-height: var(--markdown-line-height);\n }\n\n /* Images */\n .markdown img {\n /**\n * With `display: block` <a><img></a> will take the whole width.\n *\n * @see https://github.com/scalar/scalar/issues/3961\n */\n display: inline-block;\n overflow: hidden;\n border-radius: var(--scalar-radius-md);\n max-width: 100%;\n }\n\n /* Lists */\n .markdown ul,\n .markdown ol {\n display: flex;\n flex-direction: column;\n padding-left: 1.6em;\n gap: 2px;\n line-height: var(--markdown-line-height);\n }\n\n .markdown li {\n margin-top: 2px;\n padding-left: 7px;\n }\n\n ol > li::marker,\n ol > * > li::marker {\n font: var(--scalar-font);\n font-variant-numeric: tabular-nums;\n font-weight: var(--scalar-semibold);\n white-space: nowrap;\n }\n\n /* Level 1, 4, 7 → decimal */\n .markdown ol {\n list-style-type: decimal;\n }\n /* Level 2, 5, 8 → lower-alpha */\n .markdown ol ol {\n list-style-type: lower-alpha;\n }\n\n .markdown ol ol ol ol,\n .markdown ol ol ol ol ol ol ol {\n list-style-type: decimal;\n }\n\n .markdown ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol {\n list-style-type: lower-alpha;\n }\n\n /* Level 3, 6, 9 → lower-roman */\n .markdown ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ol ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ul > li,\n .markdown ul > * > li {\n list-style-type: disc;\n }\n\n /* Tables */\n .markdown table {\n display: table;\n table-layout: fixed;\n overflow-x: auto;\n position: relative;\n width: max-content;\n max-width: 100%;\n margin: 1em 0;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-md);\n border-spacing: 0;\n }\n\n .markdown tbody,\n .markdown thead {\n vertical-align: middle;\n }\n\n .markdown tbody {\n display: table-row-group;\n }\n\n .markdown thead {\n display: table-header-group;\n }\n\n .markdown tr {\n display: table-row;\n border-color: inherit;\n vertical-align: inherit;\n }\n\n .markdown td,\n .markdown th {\n display: table-cell;\n vertical-align: top;\n min-width: 1em;\n padding: 8.5px 16px;\n line-height: var(--markdown-line-height);\n position: relative;\n /** Break long words in tables */\n word-break: break-word;\n font-size: var(--scalar-small);\n color: var(--scalar-color-1);\n border-right: var(--markdown-border);\n border-bottom: var(--markdown-border);\n }\n\n .markdown td > *,\n .markdown th > * {\n margin-bottom: 0;\n }\n\n .markdown th:empty {\n display: none;\n }\n\n .markdown td:first-of-type,\n .markdown th:first-of-type {\n border-left: none;\n }\n\n .markdown td:last-of-type,\n .markdown th:last-of-type {\n border-right: none;\n }\n\n .markdown tr:last-of-type td {\n border-bottom: none;\n }\n\n .markdown th {\n font-weight: var(--scalar-bold);\n text-align: left;\n border-left-color: transparent;\n background: var(--scalar-background-2);\n }\n\n .markdown th:first-of-type {\n border-top-left-radius: var(--scalar-radius-md);\n }\n\n .markdown th:last-of-type {\n border-top-right-radius: var(--scalar-radius-md);\n }\n\n .markdown tr > [align='left'] {\n text-align: left;\n }\n\n .markdown tr > [align='right'] {\n text-align: right;\n }\n\n .markdown tr > [align='center'] {\n text-align: center;\n }\n\n /* Details */\n .markdown details {\n border: var(--markdown-border);\n border-radius: var(--scalar-radius-xl);\n color: var(--scalar-color-1);\n }\n\n .markdown details > :not(summary) {\n margin: var(--markdown-spacing-md);\n margin-bottom: 0;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) {\n margin-bottom: 8px;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) + * {\n margin-top: 0;\n }\n\n .markdown details > table {\n width: calc(100% - calc(var(--markdown-spacing-md) * 2));\n }\n\n .markdown summary {\n border-radius: var(--scalar-radius);\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-height: 40px;\n padding: 7px 14px;\n position: relative;\n font-weight: var(--scalar-semibold);\n line-height: var(--markdown-line-height);\n cursor: pointer;\n user-select: none;\n }\n\n .markdown summary:hover {\n background-color: var(--scalar-background-2);\n }\n\n .markdown details[open] {\n padding-bottom: var(--markdown-spacing-md);\n }\n\n .markdown details[open] > summary {\n border-bottom: var(--markdown-border);\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n .markdown summary::before {\n display: block;\n content: '';\n flex-shrink: 0;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n background-color: var(--scalar-color-3);\n mask-image: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" width=\"1em\" height=\"1em\"><path d=\"M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z\"></path></svg>');\n margin-top: 5px;\n }\n\n .markdown summary:hover::before {\n background-color: var(--scalar-color-1);\n }\n\n .markdown details[open] > summary::before {\n transform: rotate(90deg);\n transition: transform 0.1s ease-in-out;\n }\n\n .markdown details:has(+ details) {\n border-bottom: 0;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n margin-bottom: 0;\n }\n\n .markdown details:has(+ details) + details,\n .markdown details:has(+ details) + details > summary {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n\n /* Links */\n .markdown a {\n --font-color: var(--scalar-link-color, var(--scalar-color-accent));\n --font-visited: var(--scalar-link-color-visited, var(--scalar-color-2));\n text-decoration: var(--scalar-text-decoration);\n\n color: var(--font-color);\n font-weight: var(--scalar-link-font-weight, var(--scalar-semibold));\n text-underline-offset: 0.25rem;\n text-decoration-thickness: 1px;\n text-decoration-color: color-mix(\n in srgb,\n var(--font-color) 30%,\n transparent\n );\n }\n\n .markdown a:hover {\n text-decoration-color: var(--scalar-color-1, currentColor);\n color: var(--scalar-link-color-hover, var(--scalar-color-accent));\n -webkit-text-decoration: var(--scalar-text-decoration-hover);\n text-decoration: var(--scalar-text-decoration-hover);\n }\n\n .markdown a:visited {\n color: var(--font-visited);\n }\n\n /* Text effects and formatting */\n .markdown em {\n font-style: italic;\n }\n\n .markdown sup,\n .markdown sub {\n font-size: var(--scalar-micro);\n font-weight: 450;\n }\n\n .markdown sup {\n vertical-align: super;\n }\n\n .markdown sub {\n vertical-align: sub;\n }\n\n .markdown del {\n text-decoration: line-through;\n }\n\n /* Code blocks and inline code */\n .markdown code {\n font-family: var(--scalar-font-code);\n background-color: var(--scalar-background-2);\n box-shadow: 0 0 0 var(--scalar-border-width) var(--scalar-border-color);\n font-size: var(--scalar-micro);\n border-radius: var(--scalar-radius-md);\n padding: 0 3px;\n }\n\n .markdown .hljs {\n font-size: var(--scalar-small);\n }\n\n .markdown pre code {\n display: block;\n white-space: pre;\n padding: var(--markdown-spacing-sm);\n line-height: 1.5;\n margin: var(--markdown-spacing-sm) 0;\n -webkit-overflow-scrolling: touch;\n overflow-x: auto;\n max-width: 100%;\n min-width: 100px;\n }\n\n /* Horizontal rules */\n .markdown hr {\n border: none;\n border-bottom: var(--markdown-border);\n }\n\n /* Blockquotes */\n .markdown blockquote {\n border-left: 2px solid var(--scalar-border-color);\n padding-left: var(--markdown-spacing-sm);\n }\n\n .markdown blockquote > * {\n margin-bottom: var(--markdown-spacing-sm);\n }\n\n /* Markdown Checklist */\n .markdown li.task-list-item {\n position: relative;\n list-style: none;\n }\n\n .markdown li.task-list-item > input {\n display: inline;\n position: absolute;\n top: 0.225em;\n left: -1.4em;\n appearance: none;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n border: 1px solid var(--scalar-color-3);\n border-radius: var(--scalar-radius);\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked {\n background-color: var(--scalar-color-1);\n border-color: var(--scalar-color-1);\n }\n\n .markdown li.task-list-item > input[type='checkbox']::before {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 10px;\n border: solid var(--scalar-background-1);\n border-width: 0 1.5px 1.5px 0;\n transform: rotate(45deg);\n opacity: 0;\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked::before {\n opacity: 1;\n }\n\n /* Markdown Alert */\n .markdown .markdown-alert {\n align-items: stretch;\n border-radius: var(--scalar-radius-md);\n background-color: color-mix(\n in srgb,\n var(--scalar-background-2),\n transparent\n );\n border: var(--markdown-border);\n display: flex;\n gap: var(--markdown-spacing-sm);\n padding: 10px 14px;\n position: relative;\n }\n\n .markdown .markdown-alert .markdown-alert-icon::before {\n content: '';\n display: block;\n width: 18px;\n height: 18px;\n background-color: currentColor;\n flex-shrink: 0;\n margin-top: 3px;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n }\n\n .markdown .markdown-alert.markdown-alert-note {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-blue),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-blue), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-tip {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-2),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-2), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before,\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z\"></path></svg>');\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-important,\n .markdown .markdown-alert.markdown-alert-warning {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-orange),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-orange), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before,\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z\"></path></svg>');\n }\n\n .markdown .markdown-alert.markdown-alert-caution {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-red),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-red), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-caution\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z\"></path></svg>');\n color: var(--scalar-color-red);\n }\n\n .markdown .markdown-alert.markdown-alert-success {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-green),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-green), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-success\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z\"></path></svg>');\n color: var(--scalar-color-green);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before {\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n color: var(--scalar-color-2);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before {\n color: var(--scalar-color-purple);\n }\n\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n color: var(--scalar-color-orange);\n }\n\n .markdown .markdown-alert .markdown-alert-content {\n margin: 0;\n line-height: var(--markdown-line-height);\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarMarkdown.vue.script.js","names":[],"sources":["../../../src/components/ScalarMarkdown/ScalarMarkdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Markdown component\n *\n * Renders a markdown string as styled HTML with support for\n * headings, links, code blocks, tables, alerts, and more.\n *\n * @example\n * <ScalarMarkdown value=\"# Hello World\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n type Node,\n htmlFromMarkdown,\n isHeading,\n textFromNode,\n} from '@scalar/code-highlight'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useTemplateRef } from 'vue'\n\nimport type { ScalarMarkdownProps } from './types'\n\nconst {\n value,\n transform,\n transformType,\n withImages = false,\n withAnchors = false,\n anchorPrefix,\n} = defineProps<ScalarMarkdownProps>()\n\nconst { cx } = useBindCx()\ndefineOptions({ inheritAttrs: false })\n\n// Expose the element ref to the parent component\nconst templateRef = useTemplateRef('div')\ndefineExpose({ el: templateRef })\n\nconst transformHeading = (node: Node) => {\n if (!withAnchors) {\n return transform?.(node) || node\n }\n\n if (!isHeading(node)) {\n return node\n }\n\n const headingText = textFromNode(node)\n\n /** Basic slugify for the heading text */\n const slug = headingText.toLowerCase().replace(/\\s+/g, '-')\n\n /** Return adding anchor prefix if present or just the slug */\n const id = anchorPrefix ? `${anchorPrefix}/description/${slug}` : slug\n\n // Add the id to the heading\n node.data = {\n hProperties: {\n id,\n },\n }\n\n if (transform) {\n return transform(node)\n }\n\n return node\n}\n\nconst html = computed(() => {\n return htmlFromMarkdown(value ?? '', {\n removeTags: withImages ? [] : ['img', 'picture'],\n transform:\n withAnchors && transformType === 'heading' ? transformHeading : transform,\n transformType,\n })\n})\n</script>\n<template>\n <div\n ref=\"div\"\n v-bind=\"cx('markdown', { 'line-clamp-(--markdown-clamp)': !!clamp })\"\n :style=\"{ '--markdown-clamp': clamp }\"\n v-html=\"html\" />\n</template>\n<style>\n@import '@scalar/code-highlight/css/code.css';\n\n.scalar-app {\n /* Base container and variables */\n .markdown {\n --scalar-refs-heading-spacing: 24px;\n --markdown-border: var(--scalar-border-width) solid\n var(--scalar-border-color);\n --markdown-spacing-sm: 12px;\n --markdown-spacing-md: 16px;\n --markdown-line-height: 1.625;\n --markdown-heading-line-height: 1.15;\n\n font-family: var(--scalar-font);\n word-break: break-word;\n line-height: var(--markdown-line-height);\n }\n\n .markdown > * {\n margin-bottom: var(--markdown-spacing-md);\n }\n\n /* margin gets doubled between heading + non heading elements if we don't do this*/\n .markdown > *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):last-child {\n margin-bottom: 0;\n }\n /* Headings */\n .markdown h1,\n .markdown h2,\n .markdown h3,\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n display: block;\n font-weight: var(--scalar-bold);\n margin-top: var(--scalar-refs-heading-spacing);\n margin-bottom: var(--markdown-spacing-sm);\n line-height: var(--markdown-heading-line-height, 1.15);\n scroll-margin-top: 1rem;\n }\n .markdown h1 {\n font-size: 1.5rem;\n }\n .markdown h2,\n .markdown h3 {\n font-size: 1.25rem;\n }\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n font-size: 1rem;\n }\n\n /* Text formatting and paragraphs */\n .markdown b,\n .markdown strong {\n font-weight: var(--scalar-bold);\n }\n\n .markdown p {\n color: inherit;\n display: block;\n line-height: var(--markdown-line-height);\n }\n\n /* Images */\n .markdown img {\n /**\n * With `display: block` <a><img></a> will take the whole width.\n *\n * @see https://github.com/scalar/scalar/issues/3961\n */\n display: inline-block;\n overflow: hidden;\n border-radius: var(--scalar-radius);\n max-width: 100%;\n }\n\n /* Lists */\n .markdown ul,\n .markdown ol {\n display: flex;\n flex-direction: column;\n padding-left: 1.6em;\n gap: 2px;\n line-height: var(--markdown-line-height);\n }\n\n .markdown li {\n margin-top: 2px;\n padding-left: 7px;\n }\n\n ol > li::marker,\n ol > * > li::marker {\n font: var(--scalar-font);\n font-variant-numeric: tabular-nums;\n font-weight: var(--scalar-semibold);\n white-space: nowrap;\n }\n\n /* Level 1, 4, 7 → decimal */\n .markdown ol {\n list-style-type: decimal;\n }\n /* Level 2, 5, 8 → lower-alpha */\n .markdown ol ol {\n list-style-type: lower-alpha;\n }\n\n .markdown ol ol ol ol,\n .markdown ol ol ol ol ol ol ol {\n list-style-type: decimal;\n }\n\n .markdown ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol {\n list-style-type: lower-alpha;\n }\n\n /* Level 3, 6, 9 → lower-roman */\n .markdown ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ol ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ul > li,\n .markdown ul > * > li {\n list-style-type: disc;\n }\n\n /* Tables */\n .markdown table {\n display: table;\n table-layout: fixed;\n overflow-x: auto;\n position: relative;\n width: max-content;\n max-width: 100%;\n margin: 1em 0;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius);\n border-spacing: 0;\n }\n\n .markdown tbody,\n .markdown thead {\n vertical-align: middle;\n }\n\n .markdown tbody {\n display: table-row-group;\n }\n\n .markdown thead {\n display: table-header-group;\n }\n\n .markdown tr {\n display: table-row;\n border-color: inherit;\n vertical-align: inherit;\n }\n\n .markdown td,\n .markdown th {\n display: table-cell;\n vertical-align: top;\n min-width: 1em;\n padding: 8.5px 16px;\n line-height: var(--markdown-line-height);\n position: relative;\n /** Break long words in tables */\n word-break: break-word;\n font-size: var(--scalar-small);\n color: var(--scalar-color-1);\n border-right: var(--markdown-border);\n border-bottom: var(--markdown-border);\n }\n\n .markdown td > *,\n .markdown th > * {\n margin-bottom: 0;\n }\n\n .markdown th:empty {\n display: none;\n }\n\n .markdown td:first-of-type,\n .markdown th:first-of-type {\n border-left: none;\n }\n\n .markdown td:last-of-type,\n .markdown th:last-of-type {\n border-right: none;\n }\n\n .markdown tr:last-of-type td {\n border-bottom: none;\n }\n\n .markdown th {\n font-weight: var(--scalar-bold);\n text-align: left;\n border-left-color: transparent;\n background: var(--scalar-background-2);\n }\n\n .markdown th:first-of-type {\n border-top-left-radius: var(--scalar-radius);\n }\n\n .markdown th:last-of-type {\n border-top-right-radius: var(--scalar-radius);\n }\n\n .markdown tr > [align='left'] {\n text-align: left;\n }\n\n .markdown tr > [align='right'] {\n text-align: right;\n }\n\n .markdown tr > [align='center'] {\n text-align: center;\n }\n\n /* Details */\n .markdown details {\n border: var(--markdown-border);\n border-radius: var(--scalar-radius-xl);\n color: var(--scalar-color-1);\n }\n\n .markdown details > :not(summary) {\n margin: var(--markdown-spacing-md);\n margin-bottom: 0;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) {\n margin-bottom: 8px;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) + * {\n margin-top: 0;\n }\n\n .markdown details > table {\n width: calc(100% - calc(var(--markdown-spacing-md) * 2));\n }\n\n .markdown summary {\n border-radius: 2.5px;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-height: 40px;\n padding: 7px 14px;\n position: relative;\n font-weight: var(--scalar-semibold);\n line-height: var(--markdown-line-height);\n cursor: pointer;\n user-select: none;\n }\n\n .markdown summary:hover {\n background-color: var(--scalar-background-2);\n }\n\n .markdown details[open] {\n padding-bottom: var(--markdown-spacing-md);\n }\n\n .markdown details[open] > summary {\n border-bottom: var(--markdown-border);\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n .markdown summary::before {\n display: block;\n content: '';\n flex-shrink: 0;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n background-color: var(--scalar-color-3);\n mask-image: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" width=\"1em\" height=\"1em\"><path d=\"M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z\"></path></svg>');\n margin-top: 5px;\n }\n\n .markdown summary:hover::before {\n background-color: var(--scalar-color-1);\n }\n\n .markdown details[open] > summary::before {\n transform: rotate(90deg);\n transition: transform 0.1s ease-in-out;\n }\n\n .markdown details:has(+ details) {\n border-bottom: 0;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n margin-bottom: 0;\n }\n\n .markdown details:has(+ details) + details,\n .markdown details:has(+ details) + details > summary {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n\n /* Links */\n .markdown a {\n --font-color: var(--scalar-link-color, var(--scalar-color-accent));\n --font-visited: var(--scalar-link-color-visited, var(--scalar-color-2));\n text-decoration: var(--scalar-text-decoration);\n\n color: var(--font-color);\n font-weight: var(--scalar-link-font-weight, var(--scalar-semibold));\n text-underline-offset: 0.25rem;\n text-decoration-thickness: 1px;\n text-decoration-color: color-mix(\n in srgb,\n var(--font-color) 30%,\n transparent\n );\n }\n\n .markdown a:hover {\n text-decoration-color: var(--scalar-color-1, currentColor);\n color: var(--scalar-link-color-hover, var(--scalar-color-accent));\n -webkit-text-decoration: var(--scalar-text-decoration-hover);\n text-decoration: var(--scalar-text-decoration-hover);\n }\n\n .markdown a:visited {\n color: var(--font-visited);\n }\n\n /* Text effects and formatting */\n .markdown em {\n font-style: italic;\n }\n\n .markdown sup,\n .markdown sub {\n font-size: var(--scalar-micro);\n font-weight: 450;\n }\n\n .markdown sup {\n vertical-align: super;\n }\n\n .markdown sub {\n vertical-align: sub;\n }\n\n .markdown del {\n text-decoration: line-through;\n }\n\n /* Code blocks and inline code */\n .markdown code {\n font-family: var(--scalar-font-code);\n background-color: var(--scalar-background-2);\n box-shadow: 0 0 0 var(--scalar-border-width) var(--scalar-border-color);\n font-size: var(--scalar-micro);\n border-radius: 2px;\n padding: 0 3px;\n }\n\n .markdown .hljs {\n font-size: var(--scalar-small);\n }\n\n .markdown pre code {\n display: block;\n white-space: pre;\n padding: var(--markdown-spacing-sm);\n line-height: 1.5;\n margin: var(--markdown-spacing-sm) 0;\n -webkit-overflow-scrolling: touch;\n overflow-x: auto;\n max-width: 100%;\n min-width: 100px;\n }\n\n /* Horizontal rules */\n .markdown hr {\n border: none;\n border-bottom: var(--markdown-border);\n }\n\n /* Blockquotes */\n .markdown blockquote {\n border-left: 2px solid var(--scalar-border-color);\n padding-left: var(--markdown-spacing-sm);\n }\n\n .markdown blockquote > * {\n margin-bottom: var(--markdown-spacing-sm);\n }\n\n /* Markdown Checklist */\n .markdown li.task-list-item {\n position: relative;\n list-style: none;\n }\n\n .markdown li.task-list-item > input {\n display: inline;\n position: absolute;\n top: 0.225em;\n left: -1.4em;\n appearance: none;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n border: 1px solid var(--scalar-color-3);\n border-radius: var(--scalar-radius);\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked {\n background-color: var(--scalar-color-1);\n border-color: var(--scalar-color-1);\n }\n\n .markdown li.task-list-item > input[type='checkbox']::before {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 10px;\n border: solid var(--scalar-background-1);\n border-width: 0 1.5px 1.5px 0;\n transform: rotate(45deg);\n opacity: 0;\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked::before {\n opacity: 1;\n }\n\n /* Markdown Alert */\n .markdown .markdown-alert {\n align-items: stretch;\n border-radius: var(--scalar-radius);\n background-color: color-mix(\n in srgb,\n var(--scalar-background-2),\n transparent\n );\n border: var(--markdown-border);\n display: flex;\n gap: var(--markdown-spacing-sm);\n padding: 10px 14px;\n position: relative;\n }\n\n .markdown .markdown-alert .markdown-alert-icon::before {\n content: '';\n display: block;\n width: 18px;\n height: 18px;\n background-color: currentColor;\n flex-shrink: 0;\n margin-top: 3px;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n }\n\n .markdown .markdown-alert.markdown-alert-note {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-blue),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-blue), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-tip {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-2),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-2), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before,\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z\"></path></svg>');\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-important,\n .markdown .markdown-alert.markdown-alert-warning {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-orange),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-orange), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before,\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z\"></path></svg>');\n }\n\n .markdown .markdown-alert.markdown-alert-caution {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-red),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-red), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-caution\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z\"></path></svg>');\n color: var(--scalar-color-red);\n }\n\n .markdown .markdown-alert.markdown-alert-success {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-green),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-green), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-success\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z\"></path></svg>');\n color: var(--scalar-color-green);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before {\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n color: var(--scalar-color-2);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before {\n color: var(--scalar-color-purple);\n }\n\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n color: var(--scalar-color-orange);\n }\n\n .markdown .markdown-alert .markdown-alert-content {\n margin: 0;\n line-height: var(--markdown-line-height);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;EAkCA,MAAM,EAAE,OAAO,WAAU;AAKzB,WAAa,EAAE,IADK,eAAe,MAAK,EACR,CAAA;EAEhC,MAAM,oBAAoB,SAAe;AACvC,OAAI,CAAC,QAAA,YACH,QAAO,QAAA,YAAY,KAAK,IAAI;AAG9B,OAAI,CAAC,UAAU,KAAK,CAClB,QAAO;;GAMT,MAAM,OAHc,aAAa,KAAI,CAGZ,aAAa,CAAC,QAAQ,QAAQ,IAAG;AAM1D,QAAK,OAAO,EACV,aAAa,EACX,IALO,QAAA,eAAe,GAAG,QAAA,aAAa,eAAe,SAAS,MAM/D,EACH;AAEA,OAAI,QAAA,UACF,QAAO,QAAA,UAAU,KAAI;AAGvB,UAAO;;EAGT,MAAM,OAAO,eAAe;AAC1B,UAAO,iBAAiB,QAAA,SAAS,IAAI;IACnC,YAAY,QAAA,aAAa,EAAE,GAAG,CAAC,OAAO,UAAU;IAChD,WACE,QAAA,eAAe,QAAA,kBAAkB,YAAY,mBAAmB,QAAA;IAClE,eAAY,QAAA;IACb,CAAA;IACF;;uBAGC,mBAIkB,OAJlB,WAIkB,EAHhB,KAAI,OAAK,EACD,MAAA,GAAE,CAAA,YAAA,EAAA,iCAAA,CAAA,CAAkD,QAAA,OAAK,CAAA,EAAA;IAChE,OAAK,EAAA,oBAAwB,QAAA,OAAK;IACnC,WAAQ,KAAA"}
|
|
1
|
+
{"version":3,"file":"ScalarMarkdown.vue.script.js","names":[],"sources":["../../../src/components/ScalarMarkdown/ScalarMarkdown.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Markdown component\n *\n * Renders a markdown string as styled HTML with support for\n * headings, links, code blocks, tables, alerts, and more.\n *\n * @example\n * <ScalarMarkdown value=\"# Hello World\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n type Node,\n htmlFromMarkdown,\n isHeading,\n textFromNode,\n} from '@scalar/code-highlight'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { computed, useTemplateRef } from 'vue'\n\nimport type { ScalarMarkdownProps } from './types'\n\nconst {\n value,\n transform,\n transformType,\n withImages = false,\n withAnchors = false,\n anchorPrefix,\n} = defineProps<ScalarMarkdownProps>()\n\nconst { cx } = useBindCx()\ndefineOptions({ inheritAttrs: false })\n\n// Expose the element ref to the parent component\nconst templateRef = useTemplateRef('div')\ndefineExpose({ el: templateRef })\n\nconst transformHeading = (node: Node) => {\n if (!withAnchors) {\n return transform?.(node) || node\n }\n\n if (!isHeading(node)) {\n return node\n }\n\n const headingText = textFromNode(node)\n\n /** Basic slugify for the heading text */\n const slug = headingText.toLowerCase().replace(/\\s+/g, '-')\n\n /** Return adding anchor prefix if present or just the slug */\n const id = anchorPrefix ? `${anchorPrefix}/description/${slug}` : slug\n\n // Add the id to the heading\n node.data = {\n hProperties: {\n id,\n },\n }\n\n if (transform) {\n return transform(node)\n }\n\n return node\n}\n\nconst html = computed(() => {\n return htmlFromMarkdown(value ?? '', {\n removeTags: withImages ? [] : ['img', 'picture'],\n transform:\n withAnchors && transformType === 'heading' ? transformHeading : transform,\n transformType,\n })\n})\n</script>\n<template>\n <div\n ref=\"div\"\n v-bind=\"cx('markdown', { 'line-clamp-(--markdown-clamp)': !!clamp })\"\n :style=\"{ '--markdown-clamp': clamp }\"\n v-html=\"html\" />\n</template>\n<style>\n@import '@scalar/code-highlight/css/code.css';\n\n.scalar-app {\n /* Base container and variables */\n .markdown {\n --scalar-refs-heading-spacing: 24px;\n --markdown-border: var(--scalar-border-width) solid\n var(--scalar-border-color);\n --markdown-spacing-sm: 12px;\n --markdown-spacing-md: 16px;\n --markdown-line-height: 1.625;\n --markdown-heading-line-height: 1.15;\n\n font-family: var(--scalar-font);\n word-break: break-word;\n line-height: var(--markdown-line-height);\n }\n\n .markdown > * {\n margin-bottom: var(--markdown-spacing-md);\n }\n\n /* margin gets doubled between heading + non heading elements if we don't do this*/\n .markdown > *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):last-child {\n margin-bottom: 0;\n }\n /* Headings */\n .markdown h1,\n .markdown h2,\n .markdown h3,\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n display: block;\n font-weight: var(--scalar-bold);\n margin-top: var(--scalar-refs-heading-spacing);\n margin-bottom: var(--markdown-spacing-sm);\n line-height: var(--markdown-heading-line-height, 1.15);\n scroll-margin-top: 1rem;\n }\n .markdown h1 {\n font-size: 1.5rem;\n }\n .markdown h2,\n .markdown h3 {\n font-size: 1.25rem;\n }\n .markdown h4,\n .markdown h5,\n .markdown h6 {\n font-size: 1rem;\n }\n\n /* Text formatting and paragraphs */\n .markdown b,\n .markdown strong {\n font-weight: var(--scalar-bold);\n }\n\n .markdown p {\n color: inherit;\n display: block;\n line-height: var(--markdown-line-height);\n }\n\n /* Images */\n .markdown img {\n /**\n * With `display: block` <a><img></a> will take the whole width.\n *\n * @see https://github.com/scalar/scalar/issues/3961\n */\n display: inline-block;\n overflow: hidden;\n border-radius: var(--scalar-radius-md);\n max-width: 100%;\n }\n\n /* Lists */\n .markdown ul,\n .markdown ol {\n display: flex;\n flex-direction: column;\n padding-left: 1.6em;\n gap: 2px;\n line-height: var(--markdown-line-height);\n }\n\n .markdown li {\n margin-top: 2px;\n padding-left: 7px;\n }\n\n ol > li::marker,\n ol > * > li::marker {\n font: var(--scalar-font);\n font-variant-numeric: tabular-nums;\n font-weight: var(--scalar-semibold);\n white-space: nowrap;\n }\n\n /* Level 1, 4, 7 → decimal */\n .markdown ol {\n list-style-type: decimal;\n }\n /* Level 2, 5, 8 → lower-alpha */\n .markdown ol ol {\n list-style-type: lower-alpha;\n }\n\n .markdown ol ol ol ol,\n .markdown ol ol ol ol ol ol ol {\n list-style-type: decimal;\n }\n\n .markdown ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol {\n list-style-type: lower-alpha;\n }\n\n /* Level 3, 6, 9 → lower-roman */\n .markdown ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ol ol ol ol ol ol,\n .markdown ol ol ol ol ol ol ol ol ol {\n list-style-type: lower-roman;\n }\n\n .markdown ul > li,\n .markdown ul > * > li {\n list-style-type: disc;\n }\n\n /* Tables */\n .markdown table {\n display: table;\n table-layout: fixed;\n overflow-x: auto;\n position: relative;\n width: max-content;\n max-width: 100%;\n margin: 1em 0;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-md);\n border-spacing: 0;\n }\n\n .markdown tbody,\n .markdown thead {\n vertical-align: middle;\n }\n\n .markdown tbody {\n display: table-row-group;\n }\n\n .markdown thead {\n display: table-header-group;\n }\n\n .markdown tr {\n display: table-row;\n border-color: inherit;\n vertical-align: inherit;\n }\n\n .markdown td,\n .markdown th {\n display: table-cell;\n vertical-align: top;\n min-width: 1em;\n padding: 8.5px 16px;\n line-height: var(--markdown-line-height);\n position: relative;\n /** Break long words in tables */\n word-break: break-word;\n font-size: var(--scalar-small);\n color: var(--scalar-color-1);\n border-right: var(--markdown-border);\n border-bottom: var(--markdown-border);\n }\n\n .markdown td > *,\n .markdown th > * {\n margin-bottom: 0;\n }\n\n .markdown th:empty {\n display: none;\n }\n\n .markdown td:first-of-type,\n .markdown th:first-of-type {\n border-left: none;\n }\n\n .markdown td:last-of-type,\n .markdown th:last-of-type {\n border-right: none;\n }\n\n .markdown tr:last-of-type td {\n border-bottom: none;\n }\n\n .markdown th {\n font-weight: var(--scalar-bold);\n text-align: left;\n border-left-color: transparent;\n background: var(--scalar-background-2);\n }\n\n .markdown th:first-of-type {\n border-top-left-radius: var(--scalar-radius-md);\n }\n\n .markdown th:last-of-type {\n border-top-right-radius: var(--scalar-radius-md);\n }\n\n .markdown tr > [align='left'] {\n text-align: left;\n }\n\n .markdown tr > [align='right'] {\n text-align: right;\n }\n\n .markdown tr > [align='center'] {\n text-align: center;\n }\n\n /* Details */\n .markdown details {\n border: var(--markdown-border);\n border-radius: var(--scalar-radius-xl);\n color: var(--scalar-color-1);\n }\n\n .markdown details > :not(summary) {\n margin: var(--markdown-spacing-md);\n margin-bottom: 0;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) {\n margin-bottom: 8px;\n }\n\n .markdown details > p:has(> strong):not(:has(:not(strong))) + * {\n margin-top: 0;\n }\n\n .markdown details > table {\n width: calc(100% - calc(var(--markdown-spacing-md) * 2));\n }\n\n .markdown summary {\n border-radius: var(--scalar-radius);\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-height: 40px;\n padding: 7px 14px;\n position: relative;\n font-weight: var(--scalar-semibold);\n line-height: var(--markdown-line-height);\n cursor: pointer;\n user-select: none;\n }\n\n .markdown summary:hover {\n background-color: var(--scalar-background-2);\n }\n\n .markdown details[open] {\n padding-bottom: var(--markdown-spacing-md);\n }\n\n .markdown details[open] > summary {\n border-bottom: var(--markdown-border);\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n .markdown summary::before {\n display: block;\n content: '';\n flex-shrink: 0;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n background-color: var(--scalar-color-3);\n mask-image: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" width=\"1em\" height=\"1em\"><path d=\"M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z\"></path></svg>');\n margin-top: 5px;\n }\n\n .markdown summary:hover::before {\n background-color: var(--scalar-color-1);\n }\n\n .markdown details[open] > summary::before {\n transform: rotate(90deg);\n transition: transform 0.1s ease-in-out;\n }\n\n .markdown details:has(+ details) {\n border-bottom: 0;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n margin-bottom: 0;\n }\n\n .markdown details:has(+ details) + details,\n .markdown details:has(+ details) + details > summary {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n\n /* Links */\n .markdown a {\n --font-color: var(--scalar-link-color, var(--scalar-color-accent));\n --font-visited: var(--scalar-link-color-visited, var(--scalar-color-2));\n text-decoration: var(--scalar-text-decoration);\n\n color: var(--font-color);\n font-weight: var(--scalar-link-font-weight, var(--scalar-semibold));\n text-underline-offset: 0.25rem;\n text-decoration-thickness: 1px;\n text-decoration-color: color-mix(\n in srgb,\n var(--font-color) 30%,\n transparent\n );\n }\n\n .markdown a:hover {\n text-decoration-color: var(--scalar-color-1, currentColor);\n color: var(--scalar-link-color-hover, var(--scalar-color-accent));\n -webkit-text-decoration: var(--scalar-text-decoration-hover);\n text-decoration: var(--scalar-text-decoration-hover);\n }\n\n .markdown a:visited {\n color: var(--font-visited);\n }\n\n /* Text effects and formatting */\n .markdown em {\n font-style: italic;\n }\n\n .markdown sup,\n .markdown sub {\n font-size: var(--scalar-micro);\n font-weight: 450;\n }\n\n .markdown sup {\n vertical-align: super;\n }\n\n .markdown sub {\n vertical-align: sub;\n }\n\n .markdown del {\n text-decoration: line-through;\n }\n\n /* Code blocks and inline code */\n .markdown code {\n font-family: var(--scalar-font-code);\n background-color: var(--scalar-background-2);\n box-shadow: 0 0 0 var(--scalar-border-width) var(--scalar-border-color);\n font-size: var(--scalar-micro);\n border-radius: var(--scalar-radius-md);\n padding: 0 3px;\n }\n\n .markdown .hljs {\n font-size: var(--scalar-small);\n }\n\n .markdown pre code {\n display: block;\n white-space: pre;\n padding: var(--markdown-spacing-sm);\n line-height: 1.5;\n margin: var(--markdown-spacing-sm) 0;\n -webkit-overflow-scrolling: touch;\n overflow-x: auto;\n max-width: 100%;\n min-width: 100px;\n }\n\n /* Horizontal rules */\n .markdown hr {\n border: none;\n border-bottom: var(--markdown-border);\n }\n\n /* Blockquotes */\n .markdown blockquote {\n border-left: 2px solid var(--scalar-border-color);\n padding-left: var(--markdown-spacing-sm);\n }\n\n .markdown blockquote > * {\n margin-bottom: var(--markdown-spacing-sm);\n }\n\n /* Markdown Checklist */\n .markdown li.task-list-item {\n position: relative;\n list-style: none;\n }\n\n .markdown li.task-list-item > input {\n display: inline;\n position: absolute;\n top: 0.225em;\n left: -1.4em;\n appearance: none;\n width: var(--markdown-spacing-md);\n height: var(--markdown-spacing-md);\n border: 1px solid var(--scalar-color-3);\n border-radius: var(--scalar-radius);\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked {\n background-color: var(--scalar-color-1);\n border-color: var(--scalar-color-1);\n }\n\n .markdown li.task-list-item > input[type='checkbox']::before {\n content: '';\n position: absolute;\n left: 5px;\n top: 1px;\n width: 5px;\n height: 10px;\n border: solid var(--scalar-background-1);\n border-width: 0 1.5px 1.5px 0;\n transform: rotate(45deg);\n opacity: 0;\n }\n\n .markdown li.task-list-item > input[type='checkbox']:checked::before {\n opacity: 1;\n }\n\n /* Markdown Alert */\n .markdown .markdown-alert {\n align-items: stretch;\n border-radius: var(--scalar-radius-md);\n background-color: color-mix(\n in srgb,\n var(--scalar-background-2),\n transparent\n );\n border: var(--markdown-border);\n display: flex;\n gap: var(--markdown-spacing-sm);\n padding: 10px 14px;\n position: relative;\n }\n\n .markdown .markdown-alert .markdown-alert-icon::before {\n content: '';\n display: block;\n width: 18px;\n height: 18px;\n background-color: currentColor;\n flex-shrink: 0;\n margin-top: 3px;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n }\n\n .markdown .markdown-alert.markdown-alert-note {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-blue),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-blue), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-tip {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-2),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-2), transparent 50%);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before,\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z\"></path></svg>');\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-important,\n .markdown .markdown-alert.markdown-alert-warning {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-orange),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-orange), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before,\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z\"></path></svg>');\n }\n\n .markdown .markdown-alert.markdown-alert-caution {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-red),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-red), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-caution\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z\"></path></svg>');\n color: var(--scalar-color-red);\n }\n\n .markdown .markdown-alert.markdown-alert-success {\n background-color: color-mix(\n in srgb,\n var(--scalar-color-green),\n transparent 97%\n );\n border: var(--scalar-border-width) solid\n color-mix(in srgb, var(--scalar-color-green), transparent 50%);\n }\n\n .markdown\n .markdown-alert.markdown-alert-success\n .markdown-alert-icon::before {\n mask-image: url('data:image/svg+xml,<svg data-v-852d534d=\"\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\" class=\"icon-placeholder\"><path d=\"M173.66,98.34a8,8,0,0,1,0,11.32l-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35A8,8,0,0,1,173.66,98.34ZM232,128A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128Z\"></path></svg>');\n color: var(--scalar-color-green);\n }\n\n .markdown .markdown-alert.markdown-alert-note .markdown-alert-icon::before {\n color: var(--scalar-color-blue);\n }\n\n .markdown .markdown-alert.markdown-alert-tip .markdown-alert-icon::before {\n color: var(--scalar-color-2);\n }\n\n .markdown\n .markdown-alert.markdown-alert-important\n .markdown-alert-icon::before {\n color: var(--scalar-color-purple);\n }\n\n .markdown\n .markdown-alert.markdown-alert-warning\n .markdown-alert-icon::before {\n color: var(--scalar-color-orange);\n }\n\n .markdown .markdown-alert .markdown-alert-content {\n margin: 0;\n line-height: var(--markdown-line-height);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;EAkCA,MAAM,EAAE,OAAO,WAAU;AAKzB,WAAa,EAAE,IADK,eAAe,MAAK,EACR,CAAA;EAEhC,MAAM,oBAAoB,SAAe;AACvC,OAAI,CAAC,QAAA,YACH,QAAO,QAAA,YAAY,KAAK,IAAI;AAG9B,OAAI,CAAC,UAAU,KAAK,CAClB,QAAO;;GAMT,MAAM,OAHc,aAAa,KAAI,CAGZ,aAAa,CAAC,QAAQ,QAAQ,IAAG;AAM1D,QAAK,OAAO,EACV,aAAa,EACX,IALO,QAAA,eAAe,GAAG,QAAA,aAAa,eAAe,SAAS,MAM/D,EACH;AAEA,OAAI,QAAA,UACF,QAAO,QAAA,UAAU,KAAI;AAGvB,UAAO;;EAGT,MAAM,OAAO,eAAe;AAC1B,UAAO,iBAAiB,QAAA,SAAS,IAAI;IACnC,YAAY,QAAA,aAAa,EAAE,GAAG,CAAC,OAAO,UAAU;IAChD,WACE,QAAA,eAAe,QAAA,kBAAkB,YAAY,mBAAmB,QAAA;IAClE,eAAY,QAAA;IACb,CAAA;IACF;;uBAGC,mBAIkB,OAJlB,WAIkB,EAHhB,KAAI,OAAK,EACD,MAAA,GAAE,CAAA,YAAA,EAAA,iCAAA,CAAA,CAAkD,QAAA,OAAK,CAAA,EAAA;IAChE,OAAK,EAAA,oBAAwB,QAAA,OAAK;IACnC,WAAQ,KAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarTextArea.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"names":[],"mappings":"AA2DA;;;;;;;GAOG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;iBAqBL,MAAM;;;;iBAAN,MAAM;;;
|
|
1
|
+
{"version":3,"file":"ScalarTextArea.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"names":[],"mappings":"AA2DA;;;;;;;GAOG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;iBAqBL,MAAM;;;;iBAAN,MAAM;;;kFAuFf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarTextArea.vue.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarTextArea.vue.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none rounded-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":""}
|
|
@@ -26,7 +26,7 @@ var ScalarTextArea_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */
|
|
|
26
26
|
ref_key: "textarea",
|
|
27
27
|
ref: textarea,
|
|
28
28
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => model.value = $event)
|
|
29
|
-
}, unref(otherAttrs), { class: "w-full resize-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none" }), null, 16), [[vModelText, model.value]])]),
|
|
29
|
+
}, unref(otherAttrs), { class: "w-full resize-none rounded-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none" }), null, 16), [[vModelText, model.value]])]),
|
|
30
30
|
_: 1
|
|
31
31
|
}, 16);
|
|
32
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarTextArea.vue.script.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":";;;;;;;;;;;;;EAkBA,MAAM,QAAQ,SAAmB,SAAA,aAAgB;EAEjD,MAAM,EAAE,aAAa,oBAAoB;GACvC,OAAO;GACP,WAAW;GACZ,CAAA;EAGD,MAAM,EAAE,gBAAgB,eAAe,WAAU;AAEjD,kBAAgB;AAEd,OAAI,eAAe,WAAW,MAAO,UAAS,OAAO,OAAM;IAC5D;;uBAGC,YAakB,MAAA,wBAAA,EAblB,WAakB,EAZhB,IAAG,OAAK,EACO,MAAA,eAAc,CAAA,sGAAA,EAAA,EAK5B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,SAAQ,EAAE,OAAK,GAAA,CAAA,EAAA;
|
|
1
|
+
{"version":3,"file":"ScalarTextArea.vue.script.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none rounded-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":";;;;;;;;;;;;;EAkBA,MAAM,QAAQ,SAAmB,SAAA,aAAgB;EAEjD,MAAM,EAAE,aAAa,oBAAoB;GACvC,OAAO;GACP,WAAW;GACZ,CAAA;EAGD,MAAM,EAAE,gBAAgB,eAAe,WAAU;AAEjD,kBAAgB;AAEd,OAAI,eAAe,WAAW,MAAO,UAAS,OAAO,OAAM;IAC5D;;uBAGC,YAakB,MAAA,wBAAA,EAblB,WAakB,EAZhB,IAAG,OAAK,EACO,MAAA,eAAc,CAAA,sGAAA,EAAA,EAK5B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,SAAQ,EAAE,OAAK,GAAA,CAAA,EAAA;2BAKqG,CAAA,eAJ5H,mBAI4H,YAJ5H,WAI4H;cAHtH;KAAJ,KAAI;wEACU,QAAA;OACN,MAAA,WAAU,EAAA,EAClB,OAAM,mHAAiH,CAAA,EAAA,MAAA,GAAA,EAAA,CAAA,CAAA,YAF9G,MAAA,MAAK,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
|
|
|
2
2
|
import ScalarVirtualText_vue_vue_type_script_setup_true_lang_default from "./ScalarVirtualText.vue.script.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/components/ScalarVirtualText/ScalarVirtualText.vue
|
|
5
|
-
var ScalarVirtualText_default = /* @__PURE__ */ _plugin_vue_export_helper_default(ScalarVirtualText_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var ScalarVirtualText_default = /* @__PURE__ */ _plugin_vue_export_helper_default(ScalarVirtualText_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-77b9d685"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { ScalarVirtualText_default as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarVirtualText.vue.js","names":[],"sources":["../../../src/components/ScalarVirtualText/ScalarVirtualText.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Virtual Text component\n *\n * Renders large blocks of text efficiently using virtualized scrolling.\n * Only the visible lines are rendered to the DOM. Supports in-content\n * search with match highlighting and navigation (Cmd/Ctrl+F).\n *\n * @example\n * <ScalarVirtualText text=\"line1\\nline2\\nline3\" :lineHeight=\"20\" />\n *\n * @example\n * <ScalarVirtualText text=\"lots of text\" searchable />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nimport ScalarVirtualTextSearch from './ScalarVirtualTextSearch.vue'\n\nconst props = withDefaults(\n defineProps<{\n /** Text to display */\n text: string\n /**\n * Height of each line\n * @default 20\n */\n lineHeight?: number\n containerClass?: string\n contentClass?: string\n lineClass?: string\n /** Enable built-in search with Cmd/Ctrl+F */\n searchable?: boolean\n }>(),\n {\n lineHeight: 20,\n containerClass: '',\n contentClass: '',\n lineClass: '',\n searchable: false,\n },\n)\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst searchRef = ref<InstanceType<typeof ScalarVirtualTextSearch> | null>(null)\nconst scrollPosition = ref(0)\nconst containerHeight = ref(0)\n\nconst searchQuery = ref('')\nconst searchOpen = ref(false)\nconst activeMatchIndex = ref(0)\n\n/** Array of text broken into lines */\nconst lines = computed(() => props.text.split('\\n'))\n/** Total height of all lines combined */\nconst totalHeight = computed(() => lines.value.length * props.lineHeight)\n\n/** Index of the first visible line */\nconst visibleStartIndex = computed(() =>\n Math.floor(scrollPosition.value / props.lineHeight),\n)\n\n/** Index of the last visible line */\nconst visibleEndIndex = computed(() =>\n Math.min(\n Math.ceil(\n (scrollPosition.value + containerHeight.value) / props.lineHeight,\n ),\n lines.value.length,\n ),\n)\n\nconst BUFFER = 10\n\n/** Index of the first rendered line (clamped, shared between slice and offset) */\nconst renderStartIndex = computed(() =>\n Math.max(0, visibleStartIndex.value - BUFFER),\n)\n\n/** Array of visible lines, including buffer for smooth scrolling */\nconst visibleLines = computed(() => {\n const end = Math.min(lines.value.length, visibleEndIndex.value + BUFFER)\n return lines.value.slice(renderStartIndex.value, end)\n})\n\n/** Pixel offset for the visible content slice */\nconst contentOffset = computed(() => renderStartIndex.value * props.lineHeight)\n\n// ── Search ────────────────────────────────────────────────────────────\n\ntype SearchMatch = { line: number; start: number; end: number }\n\n/** All matches across the full text, computed only when the query changes */\nconst searchMatches = computed<SearchMatch[]>(() => {\n const query = searchQuery.value\n if (!query) return []\n\n const lowerQuery = query.toLowerCase()\n const matches: SearchMatch[] = []\n\n for (let i = 0; i < lines.value.length; i++) {\n const line = lines.value[i]\n if (!line) continue\n const lowerLine = line.toLowerCase()\n let pos = 0\n while (pos < lowerLine.length) {\n const idx = lowerLine.indexOf(lowerQuery, pos)\n if (idx === -1) break\n matches.push({ line: i, start: idx, end: idx + query.length })\n pos = idx + lowerQuery.length\n }\n }\n return matches\n})\n\n/** Set of line indices that contain at least one match, for quick lookup */\nconst matchLineSet = computed(() => {\n const set = new Set<number>()\n for (const m of searchMatches.value) set.add(m.line)\n return set\n})\n\n/** Clamp active index when match count changes */\nwatch(\n () => searchMatches.value.length,\n (count) => {\n if (count === 0) {\n activeMatchIndex.value = 0\n } else if (activeMatchIndex.value >= count) {\n activeMatchIndex.value = count - 1\n }\n },\n)\n\n/** Scroll the container so the active match's line is visible */\nconst scrollToMatch = (match: SearchMatch) => {\n if (!containerRef.value) return\n\n const targetScroll = match.line * props.lineHeight\n const viewTop = containerRef.value.scrollTop\n const viewBottom = viewTop + containerRef.value.clientHeight\n\n if (targetScroll < viewTop || targetScroll + props.lineHeight > viewBottom) {\n containerRef.value.scrollTop =\n targetScroll - containerRef.value.clientHeight / 2\n }\n}\n\nconst goToMatch = (index: number) => {\n const match = searchMatches.value[index]\n if (!match) return\n activeMatchIndex.value = index\n scrollToMatch(match)\n}\n\nconst nextMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch((activeMatchIndex.value + 1) % searchMatches.value.length)\n}\n\nconst prevMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch(\n (activeMatchIndex.value - 1 + searchMatches.value.length) %\n searchMatches.value.length,\n )\n}\n\nconst openSearch = () => {\n searchOpen.value = true\n void nextTick(() => searchRef.value?.focus())\n}\n\nconst closeSearch = () => {\n searchOpen.value = false\n searchQuery.value = ''\n activeMatchIndex.value = 0\n}\n\n/** Intercepts Cmd/Ctrl+F when searchable and the container has focus */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!props.searchable) return\n\n const modifier = e.metaKey || e.ctrlKey\n if (modifier && e.key === 'f') {\n e.preventDefault()\n e.stopPropagation()\n openSearch()\n }\n if (e.key === 'Escape' && searchOpen.value) {\n e.preventDefault()\n closeSearch()\n }\n}\n\n/** Jump to the first match whenever the query changes */\nwatch(searchQuery, () => {\n activeMatchIndex.value = 0\n const first = searchMatches.value[0]\n if (first) {\n scrollToMatch(first)\n }\n})\n\n// ── Scroll / resize ───────────────────────────────────────────────────\n\n/** Updates the scroll position when the container is scrolled */\nconst handleScroll = () =>\n containerRef.value && (scrollPosition.value = containerRef.value.scrollTop)\n\n/** Updates the container height when the window is resized */\nconst updateContainerHeight = () =>\n containerRef.value &&\n (containerHeight.value = containerRef.value.clientHeight)\n\nonMounted(() => {\n updateContainerHeight()\n window.addEventListener('resize', updateContainerHeight)\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', updateContainerHeight)\n})\n\n// ── Line rendering with highlights ────────────────────────────────────\n\ntype LineSegment = { text: string; highlight: boolean; active: boolean }\n\n/**\n * For a given absolute line index, splits the line text into segments\n * with match highlighting metadata.\n */\nconst getLineSegments = (absoluteIndex: number): LineSegment[] => {\n const lineText = lines.value[absoluteIndex] ?? ''\n if (!searchQuery.value || !matchLineSet.value.has(absoluteIndex)) {\n return [{ text: lineText, highlight: false, active: false }]\n }\n\n const lineMatches = searchMatches.value.filter(\n (m) => m.line === absoluteIndex,\n )\n const segments: LineSegment[] = []\n let cursor = 0\n\n for (const match of lineMatches) {\n if (match.start > cursor) {\n segments.push({\n text: lineText.slice(cursor, match.start),\n highlight: false,\n active: false,\n })\n }\n\n const isActive =\n searchMatches.value.indexOf(match) === activeMatchIndex.value\n\n segments.push({\n text: lineText.slice(match.start, match.end),\n highlight: true,\n active: isActive,\n })\n cursor = match.end\n }\n\n if (cursor < lineText.length) {\n segments.push({\n text: lineText.slice(cursor),\n highlight: false,\n active: false,\n })\n }\n\n return segments\n}\n\n/**\n * Converts a relative visible-line index to the absolute line index\n * in the full text.\n */\nconst toAbsoluteIndex = (relativeIndex: number): number =>\n renderStartIndex.value + relativeIndex\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"scalar-virtual-text relative overflow-auto\"\n :class=\"containerClass\"\n tabindex=\"0\"\n @keydown=\"handleKeydown\"\n @scroll=\"handleScroll\">\n <!-- Zero-height wrapper so the search bar does not contribute to scrollHeight -->\n <div\n v-if=\"searchable && searchOpen\"\n class=\"sticky top-0 z-10 flex h-0 w-full justify-end overflow-visible\">\n <ScalarVirtualTextSearch\n ref=\"searchRef\"\n v-model:query=\"searchQuery\"\n :activeMatchIndex=\"activeMatchIndex\"\n :matchCount=\"searchMatches.length\"\n @close=\"closeSearch\"\n @next=\"nextMatch\"\n @prev=\"prevMatch\" />\n </div>\n\n <!-- Invisible spacer that defines the full scrollable height -->\n <div :style=\"{ height: `${totalHeight}px` }\" />\n <code\n class=\"scalar-virtual-text-content absolute left-0 right-0 top-0\"\n :class=\"contentClass\"\n :style=\"{ transform: `translateY(${contentOffset}px)` }\">\n <div\n v-for=\"(line, index) in visibleLines\"\n :key=\"renderStartIndex + index\"\n class=\"scalar-virtual-text-line\"\n :class=\"lineClass\"\n :style=\"{\n height: `${props.lineHeight}px`,\n lineHeight: `${props.lineHeight}px`,\n }\">\n <template\n v-if=\"searchQuery && matchLineSet.has(toAbsoluteIndex(index))\">\n <template\n v-for=\"(segment, sIdx) in getLineSegments(toAbsoluteIndex(index))\"\n :key=\"sIdx\">\n <mark\n v-if=\"segment.highlight\"\n class=\"scalar-virtual-text-highlight\"\n :class=\"\n segment.active ? 'scalar-virtual-text-highlight-active' : ''\n \">\n {{ segment.text }}\n </mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </template>\n <template v-else>{{ line }}</template>\n </div>\n </code>\n </div>\n</template>\n\n<style scoped>\n.scalar-virtual-text:focus {\n outline: none;\n}\n\n.scalar-virtual-text-highlight {\n background: var(--scalar-background-accent);\n color: inherit;\n border-radius: 2px;\n padding: 1px 0;\n}\n\n.scalar-virtual-text-highlight-active {\n background: var(--scalar-color-accent);\n color: var(--scalar-background-1);\n border-radius: 2px;\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarVirtualText.vue.js","names":[],"sources":["../../../src/components/ScalarVirtualText/ScalarVirtualText.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Virtual Text component\n *\n * Renders large blocks of text efficiently using virtualized scrolling.\n * Only the visible lines are rendered to the DOM. Supports in-content\n * search with match highlighting and navigation (Cmd/Ctrl+F).\n *\n * @example\n * <ScalarVirtualText text=\"line1\\nline2\\nline3\" :lineHeight=\"20\" />\n *\n * @example\n * <ScalarVirtualText text=\"lots of text\" searchable />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nimport ScalarVirtualTextSearch from './ScalarVirtualTextSearch.vue'\n\nconst props = withDefaults(\n defineProps<{\n /** Text to display */\n text: string\n /**\n * Height of each line\n * @default 20\n */\n lineHeight?: number\n containerClass?: string\n contentClass?: string\n lineClass?: string\n /** Enable built-in search with Cmd/Ctrl+F */\n searchable?: boolean\n }>(),\n {\n lineHeight: 20,\n containerClass: '',\n contentClass: '',\n lineClass: '',\n searchable: false,\n },\n)\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst searchRef = ref<InstanceType<typeof ScalarVirtualTextSearch> | null>(null)\nconst scrollPosition = ref(0)\nconst containerHeight = ref(0)\n\nconst searchQuery = ref('')\nconst searchOpen = ref(false)\nconst activeMatchIndex = ref(0)\n\n/** Array of text broken into lines */\nconst lines = computed(() => props.text.split('\\n'))\n/** Total height of all lines combined */\nconst totalHeight = computed(() => lines.value.length * props.lineHeight)\n\n/** Index of the first visible line */\nconst visibleStartIndex = computed(() =>\n Math.floor(scrollPosition.value / props.lineHeight),\n)\n\n/** Index of the last visible line */\nconst visibleEndIndex = computed(() =>\n Math.min(\n Math.ceil(\n (scrollPosition.value + containerHeight.value) / props.lineHeight,\n ),\n lines.value.length,\n ),\n)\n\nconst BUFFER = 10\n\n/** Index of the first rendered line (clamped, shared between slice and offset) */\nconst renderStartIndex = computed(() =>\n Math.max(0, visibleStartIndex.value - BUFFER),\n)\n\n/** Array of visible lines, including buffer for smooth scrolling */\nconst visibleLines = computed(() => {\n const end = Math.min(lines.value.length, visibleEndIndex.value + BUFFER)\n return lines.value.slice(renderStartIndex.value, end)\n})\n\n/** Pixel offset for the visible content slice */\nconst contentOffset = computed(() => renderStartIndex.value * props.lineHeight)\n\n// ── Search ────────────────────────────────────────────────────────────\n\ntype SearchMatch = { line: number; start: number; end: number }\n\n/** All matches across the full text, computed only when the query changes */\nconst searchMatches = computed<SearchMatch[]>(() => {\n const query = searchQuery.value\n if (!query) return []\n\n const lowerQuery = query.toLowerCase()\n const matches: SearchMatch[] = []\n\n for (let i = 0; i < lines.value.length; i++) {\n const line = lines.value[i]\n if (!line) continue\n const lowerLine = line.toLowerCase()\n let pos = 0\n while (pos < lowerLine.length) {\n const idx = lowerLine.indexOf(lowerQuery, pos)\n if (idx === -1) break\n matches.push({ line: i, start: idx, end: idx + query.length })\n pos = idx + lowerQuery.length\n }\n }\n return matches\n})\n\n/** Set of line indices that contain at least one match, for quick lookup */\nconst matchLineSet = computed(() => {\n const set = new Set<number>()\n for (const m of searchMatches.value) set.add(m.line)\n return set\n})\n\n/** Clamp active index when match count changes */\nwatch(\n () => searchMatches.value.length,\n (count) => {\n if (count === 0) {\n activeMatchIndex.value = 0\n } else if (activeMatchIndex.value >= count) {\n activeMatchIndex.value = count - 1\n }\n },\n)\n\n/** Scroll the container so the active match's line is visible */\nconst scrollToMatch = (match: SearchMatch) => {\n if (!containerRef.value) return\n\n const targetScroll = match.line * props.lineHeight\n const viewTop = containerRef.value.scrollTop\n const viewBottom = viewTop + containerRef.value.clientHeight\n\n if (targetScroll < viewTop || targetScroll + props.lineHeight > viewBottom) {\n containerRef.value.scrollTop =\n targetScroll - containerRef.value.clientHeight / 2\n }\n}\n\nconst goToMatch = (index: number) => {\n const match = searchMatches.value[index]\n if (!match) return\n activeMatchIndex.value = index\n scrollToMatch(match)\n}\n\nconst nextMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch((activeMatchIndex.value + 1) % searchMatches.value.length)\n}\n\nconst prevMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch(\n (activeMatchIndex.value - 1 + searchMatches.value.length) %\n searchMatches.value.length,\n )\n}\n\nconst openSearch = () => {\n searchOpen.value = true\n void nextTick(() => searchRef.value?.focus())\n}\n\nconst closeSearch = () => {\n searchOpen.value = false\n searchQuery.value = ''\n activeMatchIndex.value = 0\n}\n\n/** Intercepts Cmd/Ctrl+F when searchable and the container has focus */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!props.searchable) return\n\n const modifier = e.metaKey || e.ctrlKey\n if (modifier && e.key === 'f') {\n e.preventDefault()\n e.stopPropagation()\n openSearch()\n }\n if (e.key === 'Escape' && searchOpen.value) {\n e.preventDefault()\n closeSearch()\n }\n}\n\n/** Jump to the first match whenever the query changes */\nwatch(searchQuery, () => {\n activeMatchIndex.value = 0\n const first = searchMatches.value[0]\n if (first) {\n scrollToMatch(first)\n }\n})\n\n// ── Scroll / resize ───────────────────────────────────────────────────\n\n/** Updates the scroll position when the container is scrolled */\nconst handleScroll = () =>\n containerRef.value && (scrollPosition.value = containerRef.value.scrollTop)\n\n/** Updates the container height when the window is resized */\nconst updateContainerHeight = () =>\n containerRef.value &&\n (containerHeight.value = containerRef.value.clientHeight)\n\nonMounted(() => {\n updateContainerHeight()\n window.addEventListener('resize', updateContainerHeight)\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', updateContainerHeight)\n})\n\n// ── Line rendering with highlights ────────────────────────────────────\n\ntype LineSegment = { text: string; highlight: boolean; active: boolean }\n\n/**\n * For a given absolute line index, splits the line text into segments\n * with match highlighting metadata.\n */\nconst getLineSegments = (absoluteIndex: number): LineSegment[] => {\n const lineText = lines.value[absoluteIndex] ?? ''\n if (!searchQuery.value || !matchLineSet.value.has(absoluteIndex)) {\n return [{ text: lineText, highlight: false, active: false }]\n }\n\n const lineMatches = searchMatches.value.filter(\n (m) => m.line === absoluteIndex,\n )\n const segments: LineSegment[] = []\n let cursor = 0\n\n for (const match of lineMatches) {\n if (match.start > cursor) {\n segments.push({\n text: lineText.slice(cursor, match.start),\n highlight: false,\n active: false,\n })\n }\n\n const isActive =\n searchMatches.value.indexOf(match) === activeMatchIndex.value\n\n segments.push({\n text: lineText.slice(match.start, match.end),\n highlight: true,\n active: isActive,\n })\n cursor = match.end\n }\n\n if (cursor < lineText.length) {\n segments.push({\n text: lineText.slice(cursor),\n highlight: false,\n active: false,\n })\n }\n\n return segments\n}\n\n/**\n * Converts a relative visible-line index to the absolute line index\n * in the full text.\n */\nconst toAbsoluteIndex = (relativeIndex: number): number =>\n renderStartIndex.value + relativeIndex\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"scalar-virtual-text relative overflow-auto\"\n :class=\"containerClass\"\n tabindex=\"0\"\n @keydown=\"handleKeydown\"\n @scroll=\"handleScroll\">\n <!-- Zero-height wrapper so the search bar does not contribute to scrollHeight -->\n <div\n v-if=\"searchable && searchOpen\"\n class=\"sticky top-0 z-10 flex h-0 w-full justify-end overflow-visible\">\n <ScalarVirtualTextSearch\n ref=\"searchRef\"\n v-model:query=\"searchQuery\"\n :activeMatchIndex=\"activeMatchIndex\"\n :matchCount=\"searchMatches.length\"\n @close=\"closeSearch\"\n @next=\"nextMatch\"\n @prev=\"prevMatch\" />\n </div>\n\n <!-- Invisible spacer that defines the full scrollable height -->\n <div :style=\"{ height: `${totalHeight}px` }\" />\n <code\n class=\"scalar-virtual-text-content absolute left-0 right-0 top-0\"\n :class=\"contentClass\"\n :style=\"{ transform: `translateY(${contentOffset}px)` }\">\n <div\n v-for=\"(line, index) in visibleLines\"\n :key=\"renderStartIndex + index\"\n class=\"scalar-virtual-text-line\"\n :class=\"lineClass\"\n :style=\"{\n height: `${props.lineHeight}px`,\n lineHeight: `${props.lineHeight}px`,\n }\">\n <template\n v-if=\"searchQuery && matchLineSet.has(toAbsoluteIndex(index))\">\n <template\n v-for=\"(segment, sIdx) in getLineSegments(toAbsoluteIndex(index))\"\n :key=\"sIdx\">\n <mark\n v-if=\"segment.highlight\"\n class=\"scalar-virtual-text-highlight\"\n :class=\"\n segment.active ? 'scalar-virtual-text-highlight-active' : ''\n \">\n {{ segment.text }}\n </mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </template>\n <template v-else>{{ line }}</template>\n </div>\n </code>\n </div>\n</template>\n\n<style scoped>\n.scalar-virtual-text:focus {\n outline: none;\n}\n\n.scalar-virtual-text-highlight {\n background: var(--scalar-background-accent);\n color: inherit;\n border-radius: var(--scalar-radius);\n padding: 1px 0;\n}\n\n.scalar-virtual-text-highlight-active {\n background: var(--scalar-color-accent);\n color: var(--scalar-background-1);\n border-radius: var(--scalar-radius);\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarVirtualText.vue.script.js","names":[],"sources":["../../../src/components/ScalarVirtualText/ScalarVirtualText.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Virtual Text component\n *\n * Renders large blocks of text efficiently using virtualized scrolling.\n * Only the visible lines are rendered to the DOM. Supports in-content\n * search with match highlighting and navigation (Cmd/Ctrl+F).\n *\n * @example\n * <ScalarVirtualText text=\"line1\\nline2\\nline3\" :lineHeight=\"20\" />\n *\n * @example\n * <ScalarVirtualText text=\"lots of text\" searchable />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nimport ScalarVirtualTextSearch from './ScalarVirtualTextSearch.vue'\n\nconst props = withDefaults(\n defineProps<{\n /** Text to display */\n text: string\n /**\n * Height of each line\n * @default 20\n */\n lineHeight?: number\n containerClass?: string\n contentClass?: string\n lineClass?: string\n /** Enable built-in search with Cmd/Ctrl+F */\n searchable?: boolean\n }>(),\n {\n lineHeight: 20,\n containerClass: '',\n contentClass: '',\n lineClass: '',\n searchable: false,\n },\n)\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst searchRef = ref<InstanceType<typeof ScalarVirtualTextSearch> | null>(null)\nconst scrollPosition = ref(0)\nconst containerHeight = ref(0)\n\nconst searchQuery = ref('')\nconst searchOpen = ref(false)\nconst activeMatchIndex = ref(0)\n\n/** Array of text broken into lines */\nconst lines = computed(() => props.text.split('\\n'))\n/** Total height of all lines combined */\nconst totalHeight = computed(() => lines.value.length * props.lineHeight)\n\n/** Index of the first visible line */\nconst visibleStartIndex = computed(() =>\n Math.floor(scrollPosition.value / props.lineHeight),\n)\n\n/** Index of the last visible line */\nconst visibleEndIndex = computed(() =>\n Math.min(\n Math.ceil(\n (scrollPosition.value + containerHeight.value) / props.lineHeight,\n ),\n lines.value.length,\n ),\n)\n\nconst BUFFER = 10\n\n/** Index of the first rendered line (clamped, shared between slice and offset) */\nconst renderStartIndex = computed(() =>\n Math.max(0, visibleStartIndex.value - BUFFER),\n)\n\n/** Array of visible lines, including buffer for smooth scrolling */\nconst visibleLines = computed(() => {\n const end = Math.min(lines.value.length, visibleEndIndex.value + BUFFER)\n return lines.value.slice(renderStartIndex.value, end)\n})\n\n/** Pixel offset for the visible content slice */\nconst contentOffset = computed(() => renderStartIndex.value * props.lineHeight)\n\n// ── Search ────────────────────────────────────────────────────────────\n\ntype SearchMatch = { line: number; start: number; end: number }\n\n/** All matches across the full text, computed only when the query changes */\nconst searchMatches = computed<SearchMatch[]>(() => {\n const query = searchQuery.value\n if (!query) return []\n\n const lowerQuery = query.toLowerCase()\n const matches: SearchMatch[] = []\n\n for (let i = 0; i < lines.value.length; i++) {\n const line = lines.value[i]\n if (!line) continue\n const lowerLine = line.toLowerCase()\n let pos = 0\n while (pos < lowerLine.length) {\n const idx = lowerLine.indexOf(lowerQuery, pos)\n if (idx === -1) break\n matches.push({ line: i, start: idx, end: idx + query.length })\n pos = idx + lowerQuery.length\n }\n }\n return matches\n})\n\n/** Set of line indices that contain at least one match, for quick lookup */\nconst matchLineSet = computed(() => {\n const set = new Set<number>()\n for (const m of searchMatches.value) set.add(m.line)\n return set\n})\n\n/** Clamp active index when match count changes */\nwatch(\n () => searchMatches.value.length,\n (count) => {\n if (count === 0) {\n activeMatchIndex.value = 0\n } else if (activeMatchIndex.value >= count) {\n activeMatchIndex.value = count - 1\n }\n },\n)\n\n/** Scroll the container so the active match's line is visible */\nconst scrollToMatch = (match: SearchMatch) => {\n if (!containerRef.value) return\n\n const targetScroll = match.line * props.lineHeight\n const viewTop = containerRef.value.scrollTop\n const viewBottom = viewTop + containerRef.value.clientHeight\n\n if (targetScroll < viewTop || targetScroll + props.lineHeight > viewBottom) {\n containerRef.value.scrollTop =\n targetScroll - containerRef.value.clientHeight / 2\n }\n}\n\nconst goToMatch = (index: number) => {\n const match = searchMatches.value[index]\n if (!match) return\n activeMatchIndex.value = index\n scrollToMatch(match)\n}\n\nconst nextMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch((activeMatchIndex.value + 1) % searchMatches.value.length)\n}\n\nconst prevMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch(\n (activeMatchIndex.value - 1 + searchMatches.value.length) %\n searchMatches.value.length,\n )\n}\n\nconst openSearch = () => {\n searchOpen.value = true\n void nextTick(() => searchRef.value?.focus())\n}\n\nconst closeSearch = () => {\n searchOpen.value = false\n searchQuery.value = ''\n activeMatchIndex.value = 0\n}\n\n/** Intercepts Cmd/Ctrl+F when searchable and the container has focus */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!props.searchable) return\n\n const modifier = e.metaKey || e.ctrlKey\n if (modifier && e.key === 'f') {\n e.preventDefault()\n e.stopPropagation()\n openSearch()\n }\n if (e.key === 'Escape' && searchOpen.value) {\n e.preventDefault()\n closeSearch()\n }\n}\n\n/** Jump to the first match whenever the query changes */\nwatch(searchQuery, () => {\n activeMatchIndex.value = 0\n const first = searchMatches.value[0]\n if (first) {\n scrollToMatch(first)\n }\n})\n\n// ── Scroll / resize ───────────────────────────────────────────────────\n\n/** Updates the scroll position when the container is scrolled */\nconst handleScroll = () =>\n containerRef.value && (scrollPosition.value = containerRef.value.scrollTop)\n\n/** Updates the container height when the window is resized */\nconst updateContainerHeight = () =>\n containerRef.value &&\n (containerHeight.value = containerRef.value.clientHeight)\n\nonMounted(() => {\n updateContainerHeight()\n window.addEventListener('resize', updateContainerHeight)\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', updateContainerHeight)\n})\n\n// ── Line rendering with highlights ────────────────────────────────────\n\ntype LineSegment = { text: string; highlight: boolean; active: boolean }\n\n/**\n * For a given absolute line index, splits the line text into segments\n * with match highlighting metadata.\n */\nconst getLineSegments = (absoluteIndex: number): LineSegment[] => {\n const lineText = lines.value[absoluteIndex] ?? ''\n if (!searchQuery.value || !matchLineSet.value.has(absoluteIndex)) {\n return [{ text: lineText, highlight: false, active: false }]\n }\n\n const lineMatches = searchMatches.value.filter(\n (m) => m.line === absoluteIndex,\n )\n const segments: LineSegment[] = []\n let cursor = 0\n\n for (const match of lineMatches) {\n if (match.start > cursor) {\n segments.push({\n text: lineText.slice(cursor, match.start),\n highlight: false,\n active: false,\n })\n }\n\n const isActive =\n searchMatches.value.indexOf(match) === activeMatchIndex.value\n\n segments.push({\n text: lineText.slice(match.start, match.end),\n highlight: true,\n active: isActive,\n })\n cursor = match.end\n }\n\n if (cursor < lineText.length) {\n segments.push({\n text: lineText.slice(cursor),\n highlight: false,\n active: false,\n })\n }\n\n return segments\n}\n\n/**\n * Converts a relative visible-line index to the absolute line index\n * in the full text.\n */\nconst toAbsoluteIndex = (relativeIndex: number): number =>\n renderStartIndex.value + relativeIndex\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"scalar-virtual-text relative overflow-auto\"\n :class=\"containerClass\"\n tabindex=\"0\"\n @keydown=\"handleKeydown\"\n @scroll=\"handleScroll\">\n <!-- Zero-height wrapper so the search bar does not contribute to scrollHeight -->\n <div\n v-if=\"searchable && searchOpen\"\n class=\"sticky top-0 z-10 flex h-0 w-full justify-end overflow-visible\">\n <ScalarVirtualTextSearch\n ref=\"searchRef\"\n v-model:query=\"searchQuery\"\n :activeMatchIndex=\"activeMatchIndex\"\n :matchCount=\"searchMatches.length\"\n @close=\"closeSearch\"\n @next=\"nextMatch\"\n @prev=\"prevMatch\" />\n </div>\n\n <!-- Invisible spacer that defines the full scrollable height -->\n <div :style=\"{ height: `${totalHeight}px` }\" />\n <code\n class=\"scalar-virtual-text-content absolute left-0 right-0 top-0\"\n :class=\"contentClass\"\n :style=\"{ transform: `translateY(${contentOffset}px)` }\">\n <div\n v-for=\"(line, index) in visibleLines\"\n :key=\"renderStartIndex + index\"\n class=\"scalar-virtual-text-line\"\n :class=\"lineClass\"\n :style=\"{\n height: `${props.lineHeight}px`,\n lineHeight: `${props.lineHeight}px`,\n }\">\n <template\n v-if=\"searchQuery && matchLineSet.has(toAbsoluteIndex(index))\">\n <template\n v-for=\"(segment, sIdx) in getLineSegments(toAbsoluteIndex(index))\"\n :key=\"sIdx\">\n <mark\n v-if=\"segment.highlight\"\n class=\"scalar-virtual-text-highlight\"\n :class=\"\n segment.active ? 'scalar-virtual-text-highlight-active' : ''\n \">\n {{ segment.text }}\n </mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </template>\n <template v-else>{{ line }}</template>\n </div>\n </code>\n </div>\n</template>\n\n<style scoped>\n.scalar-virtual-text:focus {\n outline: none;\n}\n\n.scalar-virtual-text-highlight {\n background: var(--scalar-background-accent);\n color: inherit;\n border-radius: 2px;\n padding: 1px 0;\n}\n\n.scalar-virtual-text-highlight-active {\n background: var(--scalar-color-accent);\n color: var(--scalar-background-1);\n border-radius: 2px;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScalarVirtualText.vue.script.js","names":[],"sources":["../../../src/components/ScalarVirtualText/ScalarVirtualText.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Virtual Text component\n *\n * Renders large blocks of text efficiently using virtualized scrolling.\n * Only the visible lines are rendered to the DOM. Supports in-content\n * search with match highlighting and navigation (Cmd/Ctrl+F).\n *\n * @example\n * <ScalarVirtualText text=\"line1\\nline2\\nline3\" :lineHeight=\"20\" />\n *\n * @example\n * <ScalarVirtualText text=\"lots of text\" searchable />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nimport ScalarVirtualTextSearch from './ScalarVirtualTextSearch.vue'\n\nconst props = withDefaults(\n defineProps<{\n /** Text to display */\n text: string\n /**\n * Height of each line\n * @default 20\n */\n lineHeight?: number\n containerClass?: string\n contentClass?: string\n lineClass?: string\n /** Enable built-in search with Cmd/Ctrl+F */\n searchable?: boolean\n }>(),\n {\n lineHeight: 20,\n containerClass: '',\n contentClass: '',\n lineClass: '',\n searchable: false,\n },\n)\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst searchRef = ref<InstanceType<typeof ScalarVirtualTextSearch> | null>(null)\nconst scrollPosition = ref(0)\nconst containerHeight = ref(0)\n\nconst searchQuery = ref('')\nconst searchOpen = ref(false)\nconst activeMatchIndex = ref(0)\n\n/** Array of text broken into lines */\nconst lines = computed(() => props.text.split('\\n'))\n/** Total height of all lines combined */\nconst totalHeight = computed(() => lines.value.length * props.lineHeight)\n\n/** Index of the first visible line */\nconst visibleStartIndex = computed(() =>\n Math.floor(scrollPosition.value / props.lineHeight),\n)\n\n/** Index of the last visible line */\nconst visibleEndIndex = computed(() =>\n Math.min(\n Math.ceil(\n (scrollPosition.value + containerHeight.value) / props.lineHeight,\n ),\n lines.value.length,\n ),\n)\n\nconst BUFFER = 10\n\n/** Index of the first rendered line (clamped, shared between slice and offset) */\nconst renderStartIndex = computed(() =>\n Math.max(0, visibleStartIndex.value - BUFFER),\n)\n\n/** Array of visible lines, including buffer for smooth scrolling */\nconst visibleLines = computed(() => {\n const end = Math.min(lines.value.length, visibleEndIndex.value + BUFFER)\n return lines.value.slice(renderStartIndex.value, end)\n})\n\n/** Pixel offset for the visible content slice */\nconst contentOffset = computed(() => renderStartIndex.value * props.lineHeight)\n\n// ── Search ────────────────────────────────────────────────────────────\n\ntype SearchMatch = { line: number; start: number; end: number }\n\n/** All matches across the full text, computed only when the query changes */\nconst searchMatches = computed<SearchMatch[]>(() => {\n const query = searchQuery.value\n if (!query) return []\n\n const lowerQuery = query.toLowerCase()\n const matches: SearchMatch[] = []\n\n for (let i = 0; i < lines.value.length; i++) {\n const line = lines.value[i]\n if (!line) continue\n const lowerLine = line.toLowerCase()\n let pos = 0\n while (pos < lowerLine.length) {\n const idx = lowerLine.indexOf(lowerQuery, pos)\n if (idx === -1) break\n matches.push({ line: i, start: idx, end: idx + query.length })\n pos = idx + lowerQuery.length\n }\n }\n return matches\n})\n\n/** Set of line indices that contain at least one match, for quick lookup */\nconst matchLineSet = computed(() => {\n const set = new Set<number>()\n for (const m of searchMatches.value) set.add(m.line)\n return set\n})\n\n/** Clamp active index when match count changes */\nwatch(\n () => searchMatches.value.length,\n (count) => {\n if (count === 0) {\n activeMatchIndex.value = 0\n } else if (activeMatchIndex.value >= count) {\n activeMatchIndex.value = count - 1\n }\n },\n)\n\n/** Scroll the container so the active match's line is visible */\nconst scrollToMatch = (match: SearchMatch) => {\n if (!containerRef.value) return\n\n const targetScroll = match.line * props.lineHeight\n const viewTop = containerRef.value.scrollTop\n const viewBottom = viewTop + containerRef.value.clientHeight\n\n if (targetScroll < viewTop || targetScroll + props.lineHeight > viewBottom) {\n containerRef.value.scrollTop =\n targetScroll - containerRef.value.clientHeight / 2\n }\n}\n\nconst goToMatch = (index: number) => {\n const match = searchMatches.value[index]\n if (!match) return\n activeMatchIndex.value = index\n scrollToMatch(match)\n}\n\nconst nextMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch((activeMatchIndex.value + 1) % searchMatches.value.length)\n}\n\nconst prevMatch = () => {\n if (searchMatches.value.length === 0) return\n goToMatch(\n (activeMatchIndex.value - 1 + searchMatches.value.length) %\n searchMatches.value.length,\n )\n}\n\nconst openSearch = () => {\n searchOpen.value = true\n void nextTick(() => searchRef.value?.focus())\n}\n\nconst closeSearch = () => {\n searchOpen.value = false\n searchQuery.value = ''\n activeMatchIndex.value = 0\n}\n\n/** Intercepts Cmd/Ctrl+F when searchable and the container has focus */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!props.searchable) return\n\n const modifier = e.metaKey || e.ctrlKey\n if (modifier && e.key === 'f') {\n e.preventDefault()\n e.stopPropagation()\n openSearch()\n }\n if (e.key === 'Escape' && searchOpen.value) {\n e.preventDefault()\n closeSearch()\n }\n}\n\n/** Jump to the first match whenever the query changes */\nwatch(searchQuery, () => {\n activeMatchIndex.value = 0\n const first = searchMatches.value[0]\n if (first) {\n scrollToMatch(first)\n }\n})\n\n// ── Scroll / resize ───────────────────────────────────────────────────\n\n/** Updates the scroll position when the container is scrolled */\nconst handleScroll = () =>\n containerRef.value && (scrollPosition.value = containerRef.value.scrollTop)\n\n/** Updates the container height when the window is resized */\nconst updateContainerHeight = () =>\n containerRef.value &&\n (containerHeight.value = containerRef.value.clientHeight)\n\nonMounted(() => {\n updateContainerHeight()\n window.addEventListener('resize', updateContainerHeight)\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', updateContainerHeight)\n})\n\n// ── Line rendering with highlights ────────────────────────────────────\n\ntype LineSegment = { text: string; highlight: boolean; active: boolean }\n\n/**\n * For a given absolute line index, splits the line text into segments\n * with match highlighting metadata.\n */\nconst getLineSegments = (absoluteIndex: number): LineSegment[] => {\n const lineText = lines.value[absoluteIndex] ?? ''\n if (!searchQuery.value || !matchLineSet.value.has(absoluteIndex)) {\n return [{ text: lineText, highlight: false, active: false }]\n }\n\n const lineMatches = searchMatches.value.filter(\n (m) => m.line === absoluteIndex,\n )\n const segments: LineSegment[] = []\n let cursor = 0\n\n for (const match of lineMatches) {\n if (match.start > cursor) {\n segments.push({\n text: lineText.slice(cursor, match.start),\n highlight: false,\n active: false,\n })\n }\n\n const isActive =\n searchMatches.value.indexOf(match) === activeMatchIndex.value\n\n segments.push({\n text: lineText.slice(match.start, match.end),\n highlight: true,\n active: isActive,\n })\n cursor = match.end\n }\n\n if (cursor < lineText.length) {\n segments.push({\n text: lineText.slice(cursor),\n highlight: false,\n active: false,\n })\n }\n\n return segments\n}\n\n/**\n * Converts a relative visible-line index to the absolute line index\n * in the full text.\n */\nconst toAbsoluteIndex = (relativeIndex: number): number =>\n renderStartIndex.value + relativeIndex\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"scalar-virtual-text relative overflow-auto\"\n :class=\"containerClass\"\n tabindex=\"0\"\n @keydown=\"handleKeydown\"\n @scroll=\"handleScroll\">\n <!-- Zero-height wrapper so the search bar does not contribute to scrollHeight -->\n <div\n v-if=\"searchable && searchOpen\"\n class=\"sticky top-0 z-10 flex h-0 w-full justify-end overflow-visible\">\n <ScalarVirtualTextSearch\n ref=\"searchRef\"\n v-model:query=\"searchQuery\"\n :activeMatchIndex=\"activeMatchIndex\"\n :matchCount=\"searchMatches.length\"\n @close=\"closeSearch\"\n @next=\"nextMatch\"\n @prev=\"prevMatch\" />\n </div>\n\n <!-- Invisible spacer that defines the full scrollable height -->\n <div :style=\"{ height: `${totalHeight}px` }\" />\n <code\n class=\"scalar-virtual-text-content absolute left-0 right-0 top-0\"\n :class=\"contentClass\"\n :style=\"{ transform: `translateY(${contentOffset}px)` }\">\n <div\n v-for=\"(line, index) in visibleLines\"\n :key=\"renderStartIndex + index\"\n class=\"scalar-virtual-text-line\"\n :class=\"lineClass\"\n :style=\"{\n height: `${props.lineHeight}px`,\n lineHeight: `${props.lineHeight}px`,\n }\">\n <template\n v-if=\"searchQuery && matchLineSet.has(toAbsoluteIndex(index))\">\n <template\n v-for=\"(segment, sIdx) in getLineSegments(toAbsoluteIndex(index))\"\n :key=\"sIdx\">\n <mark\n v-if=\"segment.highlight\"\n class=\"scalar-virtual-text-highlight\"\n :class=\"\n segment.active ? 'scalar-virtual-text-highlight-active' : ''\n \">\n {{ segment.text }}\n </mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </template>\n <template v-else>{{ line }}</template>\n </div>\n </code>\n </div>\n</template>\n\n<style scoped>\n.scalar-virtual-text:focus {\n outline: none;\n}\n\n.scalar-virtual-text-highlight {\n background: var(--scalar-background-accent);\n color: inherit;\n border-radius: var(--scalar-radius);\n padding: 1px 0;\n}\n\n.scalar-virtual-text-highlight-active {\n background: var(--scalar-color-accent);\n color: var(--scalar-background-1);\n border-radius: var(--scalar-radius);\n}\n</style>\n"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -99,8 +99,13 @@
|
|
|
99
99
|
:root {
|
|
100
100
|
--scalar-border-width: .5px;
|
|
101
101
|
--scalar-radius: 3px;
|
|
102
|
-
--scalar-radius-
|
|
103
|
-
--scalar-radius-
|
|
102
|
+
--scalar-radius-max: 20px;
|
|
103
|
+
--scalar-radius-md: min(var(--scalar-radius), var(--scalar-radius-max));
|
|
104
|
+
--scalar-radius-lg: min(calc(var(--scalar-radius) * 2), var(--scalar-radius-max));
|
|
105
|
+
--scalar-radius-xl: min(calc(var(--scalar-radius) * 8 / 3), var(--scalar-radius-max));
|
|
106
|
+
--scalar-radius-2xl: min(calc(var(--scalar-radius) * 4), var(--scalar-radius-max));
|
|
107
|
+
--scalar-radius-3xl: min(calc(var(--scalar-radius) * 16 / 3), var(--scalar-radius-max));
|
|
108
|
+
--scalar-radius-full: calc(var(--scalar-radius) * 9999);
|
|
104
109
|
--scalar-font: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
|
105
110
|
"Noto Color Emoji";
|
|
106
111
|
--scalar-font-code: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
@@ -436,7 +441,7 @@
|
|
|
436
441
|
}
|
|
437
442
|
|
|
438
443
|
:where(.scalar-app) input:where(:not([type="button"], [type="reset"], [type="submit"])), :where(.scalar-app) select, :where(.scalar-app) textarea {
|
|
439
|
-
border-radius: var(--scalar-radius);
|
|
444
|
+
border-radius: var(--scalar-radius-md);
|
|
440
445
|
border-width: 1px;
|
|
441
446
|
}
|
|
442
447
|
|
|
@@ -472,7 +477,6 @@
|
|
|
472
477
|
}
|
|
473
478
|
|
|
474
479
|
:where(.scalar-app) :focus-visible {
|
|
475
|
-
border-radius: var(--scalar-radius);
|
|
476
480
|
outline-style: solid;
|
|
477
481
|
}
|
|
478
482
|
|
|
@@ -1721,7 +1725,15 @@
|
|
|
1721
1725
|
}
|
|
1722
1726
|
|
|
1723
1727
|
.scalar-app .rounded {
|
|
1724
|
-
border-radius: var(--scalar-radius);
|
|
1728
|
+
border-radius: var(--scalar-radius-md);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
.scalar-app .rounded-2xl {
|
|
1732
|
+
border-radius: var(--scalar-radius-2xl);
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
.scalar-app .rounded-3xl {
|
|
1736
|
+
border-radius: var(--scalar-radius-3xl);
|
|
1725
1737
|
}
|
|
1726
1738
|
|
|
1727
1739
|
.scalar-app .rounded-\[inherit\] {
|
|
@@ -1729,7 +1741,7 @@
|
|
|
1729
1741
|
}
|
|
1730
1742
|
|
|
1731
1743
|
.scalar-app .rounded-full {
|
|
1732
|
-
border-radius:
|
|
1744
|
+
border-radius: var(--scalar-radius-full);
|
|
1733
1745
|
}
|
|
1734
1746
|
|
|
1735
1747
|
.scalar-app .rounded-lg {
|
|
@@ -1737,7 +1749,7 @@
|
|
|
1737
1749
|
}
|
|
1738
1750
|
|
|
1739
1751
|
.scalar-app .rounded-md {
|
|
1740
|
-
border-radius: var(--scalar-radius);
|
|
1752
|
+
border-radius: var(--scalar-radius-md);
|
|
1741
1753
|
}
|
|
1742
1754
|
|
|
1743
1755
|
.scalar-app .rounded-none {
|
|
@@ -1748,14 +1760,19 @@
|
|
|
1748
1760
|
border-radius: var(--scalar-radius-xl);
|
|
1749
1761
|
}
|
|
1750
1762
|
|
|
1763
|
+
.scalar-app .rounded-t-\[inherit\] {
|
|
1764
|
+
border-top-left-radius: inherit;
|
|
1765
|
+
border-top-right-radius: inherit;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1751
1768
|
.scalar-app .rounded-l-none {
|
|
1752
1769
|
border-top-left-radius: 0;
|
|
1753
1770
|
border-bottom-left-radius: 0;
|
|
1754
1771
|
}
|
|
1755
1772
|
|
|
1756
1773
|
.scalar-app .rounded-b {
|
|
1757
|
-
border-bottom-right-radius: var(--scalar-radius);
|
|
1758
|
-
border-bottom-left-radius: var(--scalar-radius);
|
|
1774
|
+
border-bottom-right-radius: var(--scalar-radius-md);
|
|
1775
|
+
border-bottom-left-radius: var(--scalar-radius-md);
|
|
1759
1776
|
}
|
|
1760
1777
|
|
|
1761
1778
|
.scalar-app .border {
|
|
@@ -2446,6 +2463,11 @@
|
|
|
2446
2463
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2447
2464
|
}
|
|
2448
2465
|
|
|
2466
|
+
.scalar-app .ring {
|
|
2467
|
+
--tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
2468
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2449
2471
|
.scalar-app .outline {
|
|
2450
2472
|
outline-style: var(--tw-outline-style);
|
|
2451
2473
|
outline-width: 1px;
|
|
@@ -2625,7 +2647,7 @@
|
|
|
2625
2647
|
}
|
|
2626
2648
|
|
|
2627
2649
|
:is(.scalar-app .\*\:rounded > *) {
|
|
2628
|
-
border-radius: var(--scalar-radius);
|
|
2650
|
+
border-radius: var(--scalar-radius-md);
|
|
2629
2651
|
}
|
|
2630
2652
|
|
|
2631
2653
|
:is(.scalar-app .\*\:border > *) {
|
|
@@ -3948,7 +3970,7 @@ code.hljs {
|
|
|
3948
3970
|
*/
|
|
3949
3971
|
display: inline-block;
|
|
3950
3972
|
overflow: hidden;
|
|
3951
|
-
border-radius: var(--scalar-radius);
|
|
3973
|
+
border-radius: var(--scalar-radius-md);
|
|
3952
3974
|
max-width: 100%;
|
|
3953
3975
|
}
|
|
3954
3976
|
|
|
@@ -4013,7 +4035,7 @@ ol > li::marker,
|
|
|
4013
4035
|
max-width: 100%;
|
|
4014
4036
|
margin: 1em 0;
|
|
4015
4037
|
border: var(--scalar-border-width) solid var(--scalar-border-color);
|
|
4016
|
-
border-radius: var(--scalar-radius);
|
|
4038
|
+
border-radius: var(--scalar-radius-md);
|
|
4017
4039
|
border-spacing: 0;
|
|
4018
4040
|
}
|
|
4019
4041
|
.markdown tbody,
|
|
@@ -4071,10 +4093,10 @@ ol > li::marker,
|
|
|
4071
4093
|
background: var(--scalar-background-2);
|
|
4072
4094
|
}
|
|
4073
4095
|
.markdown th:first-of-type {
|
|
4074
|
-
border-top-left-radius: var(--scalar-radius);
|
|
4096
|
+
border-top-left-radius: var(--scalar-radius-md);
|
|
4075
4097
|
}
|
|
4076
4098
|
.markdown th:last-of-type {
|
|
4077
|
-
border-top-right-radius: var(--scalar-radius);
|
|
4099
|
+
border-top-right-radius: var(--scalar-radius-md);
|
|
4078
4100
|
}
|
|
4079
4101
|
.markdown tr > [align='left'] {
|
|
4080
4102
|
text-align: left;
|
|
@@ -4106,7 +4128,7 @@ ol > li::marker,
|
|
|
4106
4128
|
width: calc(100% - calc(var(--markdown-spacing-md) * 2));
|
|
4107
4129
|
}
|
|
4108
4130
|
.markdown summary {
|
|
4109
|
-
border-radius:
|
|
4131
|
+
border-radius: var(--scalar-radius);
|
|
4110
4132
|
display: flex;
|
|
4111
4133
|
align-items: flex-start;
|
|
4112
4134
|
gap: 8px;
|
|
@@ -4209,7 +4231,7 @@ ol > li::marker,
|
|
|
4209
4231
|
background-color: var(--scalar-background-2);
|
|
4210
4232
|
box-shadow: 0 0 0 var(--scalar-border-width) var(--scalar-border-color);
|
|
4211
4233
|
font-size: var(--scalar-micro);
|
|
4212
|
-
border-radius:
|
|
4234
|
+
border-radius: var(--scalar-radius-md);
|
|
4213
4235
|
padding: 0 3px;
|
|
4214
4236
|
}
|
|
4215
4237
|
.markdown .hljs {
|
|
@@ -4281,7 +4303,7 @@ ol > li::marker,
|
|
|
4281
4303
|
/* Markdown Alert */
|
|
4282
4304
|
.markdown .markdown-alert {
|
|
4283
4305
|
align-items: stretch;
|
|
4284
|
-
border-radius: var(--scalar-radius);
|
|
4306
|
+
border-radius: var(--scalar-radius-md);
|
|
4285
4307
|
background-color: color-mix(
|
|
4286
4308
|
in srgb,
|
|
4287
4309
|
var(--scalar-background-2),
|
|
@@ -4603,7 +4625,7 @@ to {
|
|
|
4603
4625
|
:where(body) > .scalar-tooltip:before {
|
|
4604
4626
|
content: "";
|
|
4605
4627
|
z-index: calc(1 * -1);
|
|
4606
|
-
border-radius: var(--scalar-radius);
|
|
4628
|
+
border-radius: var(--scalar-radius-md);
|
|
4607
4629
|
background-color: var(--scalar-tooltip-background);
|
|
4608
4630
|
--tw-backdrop-blur: blur(8px);
|
|
4609
4631
|
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
|
@@ -4737,18 +4759,18 @@ to {
|
|
|
4737
4759
|
display: none;
|
|
4738
4760
|
}
|
|
4739
4761
|
|
|
4740
|
-
.scalar-virtual-text[data-v-
|
|
4762
|
+
.scalar-virtual-text[data-v-77b9d685]:focus {
|
|
4741
4763
|
outline: none;
|
|
4742
4764
|
}
|
|
4743
|
-
.scalar-virtual-text-highlight[data-v-
|
|
4765
|
+
.scalar-virtual-text-highlight[data-v-77b9d685] {
|
|
4744
4766
|
background: var(--scalar-background-accent);
|
|
4745
4767
|
color: inherit;
|
|
4746
|
-
border-radius:
|
|
4768
|
+
border-radius: var(--scalar-radius);
|
|
4747
4769
|
padding: 1px 0;
|
|
4748
4770
|
}
|
|
4749
|
-
.scalar-virtual-text-highlight-active[data-v-
|
|
4771
|
+
.scalar-virtual-text-highlight-active[data-v-77b9d685] {
|
|
4750
4772
|
background: var(--scalar-color-accent);
|
|
4751
4773
|
color: var(--scalar-background-1);
|
|
4752
|
-
border-radius:
|
|
4774
|
+
border-radius: var(--scalar-radius);
|
|
4753
4775
|
}
|
|
4754
4776
|
/*$vite$:1*/
|
package/dist/vue-styles.css
CHANGED
|
@@ -527,7 +527,7 @@ code.hljs {
|
|
|
527
527
|
*/
|
|
528
528
|
display: inline-block;
|
|
529
529
|
overflow: hidden;
|
|
530
|
-
border-radius: var(--scalar-radius);
|
|
530
|
+
border-radius: var(--scalar-radius-md);
|
|
531
531
|
max-width: 100%;
|
|
532
532
|
}
|
|
533
533
|
|
|
@@ -592,7 +592,7 @@ ol > li::marker,
|
|
|
592
592
|
max-width: 100%;
|
|
593
593
|
margin: 1em 0;
|
|
594
594
|
border: var(--scalar-border-width) solid var(--scalar-border-color);
|
|
595
|
-
border-radius: var(--scalar-radius);
|
|
595
|
+
border-radius: var(--scalar-radius-md);
|
|
596
596
|
border-spacing: 0;
|
|
597
597
|
}
|
|
598
598
|
.markdown tbody,
|
|
@@ -650,10 +650,10 @@ ol > li::marker,
|
|
|
650
650
|
background: var(--scalar-background-2);
|
|
651
651
|
}
|
|
652
652
|
.markdown th:first-of-type {
|
|
653
|
-
border-top-left-radius: var(--scalar-radius);
|
|
653
|
+
border-top-left-radius: var(--scalar-radius-md);
|
|
654
654
|
}
|
|
655
655
|
.markdown th:last-of-type {
|
|
656
|
-
border-top-right-radius: var(--scalar-radius);
|
|
656
|
+
border-top-right-radius: var(--scalar-radius-md);
|
|
657
657
|
}
|
|
658
658
|
.markdown tr > [align='left'] {
|
|
659
659
|
text-align: left;
|
|
@@ -685,7 +685,7 @@ ol > li::marker,
|
|
|
685
685
|
width: calc(100% - calc(var(--markdown-spacing-md) * 2));
|
|
686
686
|
}
|
|
687
687
|
.markdown summary {
|
|
688
|
-
border-radius:
|
|
688
|
+
border-radius: var(--scalar-radius);
|
|
689
689
|
display: flex;
|
|
690
690
|
align-items: flex-start;
|
|
691
691
|
gap: 8px;
|
|
@@ -788,7 +788,7 @@ ol > li::marker,
|
|
|
788
788
|
background-color: var(--scalar-background-2);
|
|
789
789
|
box-shadow: 0 0 0 var(--scalar-border-width) var(--scalar-border-color);
|
|
790
790
|
font-size: var(--scalar-micro);
|
|
791
|
-
border-radius:
|
|
791
|
+
border-radius: var(--scalar-radius-md);
|
|
792
792
|
padding: 0 3px;
|
|
793
793
|
}
|
|
794
794
|
.markdown .hljs {
|
|
@@ -860,7 +860,7 @@ ol > li::marker,
|
|
|
860
860
|
/* Markdown Alert */
|
|
861
861
|
.markdown .markdown-alert {
|
|
862
862
|
align-items: stretch;
|
|
863
|
-
border-radius: var(--scalar-radius);
|
|
863
|
+
border-radius: var(--scalar-radius-md);
|
|
864
864
|
background-color: color-mix(
|
|
865
865
|
in srgb,
|
|
866
866
|
var(--scalar-background-2),
|
|
@@ -1182,7 +1182,7 @@ to {
|
|
|
1182
1182
|
:where(body) > .scalar-tooltip:before {
|
|
1183
1183
|
content: "";
|
|
1184
1184
|
z-index: calc(1 * -1);
|
|
1185
|
-
border-radius: var(--scalar-radius);
|
|
1185
|
+
border-radius: var(--scalar-radius-md);
|
|
1186
1186
|
background-color: var(--scalar-tooltip-background);
|
|
1187
1187
|
--tw-backdrop-blur: blur(8px);
|
|
1188
1188
|
-webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
|
|
@@ -1316,18 +1316,18 @@ to {
|
|
|
1316
1316
|
display: none;
|
|
1317
1317
|
}
|
|
1318
1318
|
|
|
1319
|
-
.scalar-virtual-text[data-v-
|
|
1319
|
+
.scalar-virtual-text[data-v-77b9d685]:focus {
|
|
1320
1320
|
outline: none;
|
|
1321
1321
|
}
|
|
1322
|
-
.scalar-virtual-text-highlight[data-v-
|
|
1322
|
+
.scalar-virtual-text-highlight[data-v-77b9d685] {
|
|
1323
1323
|
background: var(--scalar-background-accent);
|
|
1324
1324
|
color: inherit;
|
|
1325
|
-
border-radius:
|
|
1325
|
+
border-radius: var(--scalar-radius);
|
|
1326
1326
|
padding: 1px 0;
|
|
1327
1327
|
}
|
|
1328
|
-
.scalar-virtual-text-highlight-active[data-v-
|
|
1328
|
+
.scalar-virtual-text-highlight-active[data-v-77b9d685] {
|
|
1329
1329
|
background: var(--scalar-color-accent);
|
|
1330
1330
|
color: var(--scalar-background-1);
|
|
1331
|
-
border-radius:
|
|
1331
|
+
border-radius: var(--scalar-radius);
|
|
1332
1332
|
}
|
|
1333
1333
|
/*$vite$:1*/
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"url": "git+https://github.com/scalar/scalar.git",
|
|
11
11
|
"directory": "packages/components"
|
|
12
12
|
},
|
|
13
|
-
"version": "0.27.
|
|
13
|
+
"version": "0.27.9",
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=22"
|
|
16
16
|
},
|
|
@@ -221,11 +221,11 @@
|
|
|
221
221
|
"radix-vue": "^1.9.17",
|
|
222
222
|
"vue": "^3.5.30",
|
|
223
223
|
"vue-component-type-helpers": "^3.2.6",
|
|
224
|
-
"@scalar/
|
|
225
|
-
"@scalar/
|
|
226
|
-
"@scalar/
|
|
227
|
-
"@scalar/
|
|
228
|
-
"@scalar/use-hooks": "0.4.
|
|
224
|
+
"@scalar/code-highlight": "0.4.3",
|
|
225
|
+
"@scalar/helpers": "0.9.2",
|
|
226
|
+
"@scalar/themes": "0.17.1",
|
|
227
|
+
"@scalar/icons": "0.7.5",
|
|
228
|
+
"@scalar/use-hooks": "0.4.9"
|
|
229
229
|
},
|
|
230
230
|
"devDependencies": {
|
|
231
231
|
"@playwright/test": "1.59.1",
|