UNPKG

@rhds/elements

Version:

Red Hat Design System Elements

523 lines (520 loc) 35.5 kB
var _RhCodeBlock_instances, _RhCodeBlock_logger, _RhCodeBlock_slots, _RhCodeBlock_prismOutput, _RhCodeBlock_isIntersecting, _RhCodeBlock_ro, _RhCodeBlock_lines, _RhCodeBlock_lineHeights, _RhCodeBlock_onSlotChange, _RhCodeBlock_applyPrismPrerenderedStyles, _RhCodeBlock_highlightWithPrism, _RhCodeBlock_onVisibilityChange, _RhCodeBlock_updateResizeObserver, _RhCodeBlock_wrapChanged, _RhCodeBlock_setSlottedLabelState, _RhCodeBlock_getSlottedCodeElements, _RhCodeBlock_computeLines, _RhCodeBlock_computeLineNumbers, _RhCodeBlock_onActionsClick, _RhCodeBlock_onActionsKeyup, _RhCodeBlock_onCodeAction, _RhCodeBlock_onClickExpand, _RhCodeBlock_preCopy, _RhCodeBlock_copy; var RhCodeBlock_1; import { __classPrivateFieldGet, __classPrivateFieldSet, __decorate } from "tslib"; import { CSSResult, LitElement, html, isServer } from 'lit'; import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { state } from 'lit/decorators/state.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js'; import { Logger } from '@patternfly/pfe-core/controllers/logger.js'; import { themable } from '@rhds/elements/lib/themable.js'; import { css } from "lit"; const style = css `:host{--rh-code-block-callout-size:var(--rh-size-icon-02,24px);--_aspect-ratio:1;--_badge-size:var(--rh-code-block-callout-size);--_badge-padding:0;display:block;max-width:1000px;max-height:calc(var(--rh-space-4xl, 64px)*10)}:host([full-height]){--_expand-toggle-rotate:0deg;max-height:none}[hidden]{display:none!important}::slotted(pre){margin:0!important;padding:0!important;background:#0000!important;border:none!important}.shadow-fab{display:flex;align-items:center;justify-content:center;border:none;background:#0000;padding:var(--rh-space-md,8px);border-radius:var(--rh-border-radius-default,3px);width:var(--rh-length-3xl,48px);height:var(--rh-length-3xl,48px)}.shadow-fab:is(:hover,:focus,:active){background:var(--rh-color-surface)}.shadow-fab svg{width:var(--rh-size-icon-02,24px);height:var(--rh-size-icon-02,24px);color:var(--rh-color-text-primary)}#container,#content,#content-lines,#prism-output,#sizers{max-width:100%}#prism-output{margin:0}#prism-output code{font-size:inherit;font-family:inherit;font-weight:inherit;line-height:inherit}#container{--_code-background-color:light-dark(var(--rh-color-surface-lighter,#f2f2f2),oklch(from var(--rh-color-surface-dark,#383838) calc(l * 0.82) c h));--_code-main-spacer:var(--rh-space-xl,24px);--_cdata-color:var(--rh-color-text-secondary);--_comment-color:var(--rh-color-text-secondary);--_comment-block-color:var(--rh-color-text-secondary);--_doctype-color:var(--rh-color-text-secondary);--_default-color:light-dark(var(--rh-color-gray-95,#151515),var(--rh-color-gray-20,#e0e0e0));--_selected-text-background:light-dark(var(--rh-color-blue-10,#e0f0ff),var(--rh-color-gray-95,#151515));--_punctuation-color:light-dark(var(--rh-color-gray-40,#a3a3a3),var(--rh-color-gray-20,#e0e0e0));--_namespace-color:light-dark(var(--rh-color-gray-95,#151515),var(--rh-color-red-40,#f56e6e));--_property-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-yellow-40,#dca614));--_tag-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-red-10,#fce3e3));--_boolean-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-orange-40,#f5921b));--_number-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-orange-40,#f5921b));--_constant-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-yellow-40,#dca614));--_symbol-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-yellow-40,#dca614));--_deleted-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-red-40,#f56e6e));--_function-name-color:light-dark(var(--rh-color-purple-50,#5e40be),var(--rh-color-teal-20,#b9e5e5));--_selector-color:light-dark(var(--rh-color-teal-60,#147878),var(--rh-color-purple-30,#b6a6e9));--_attr-name-color:light-dark(var(--rh-color-teal-60,#147878),var(--rh-color-red-40,#f56e6e));--_string-color:light-dark(var(--rh-color-teal-60,#147878),var(--rh-color-green-40,#87bb62));--_character-color:light-dark(var(--rh-color-teal-60,#147878),var(--rh-color-green-40,#87bb62));--_built-in-color:light-dark(var(--rh-color-teal-60,#147878),var(--rh-color-purple-30,#b6a6e9));--_inserted-color:light-dark(var(--rh-color-teal-60,#147878),var(--rh-color-green-40,#87bb62));--_operator-color:light-dark(var(--rh-color-yellow-60,#96640f),var(--rh-color-blue-40,#4394e5));--_entity-color:light-dark(var(--rh-color-yellow-60,#96640f),var(--rh-color-blue-40,#4394e5));--_url-color:light-dark(var(--rh-color-yellow-60,#96640f),var(--rh-color-blue-40,#4394e5));--_at-rule-color:light-dark(var(--rh-color-blue-60,#004d99),var(--rh-color-purple-30,#b6a6e9));--_attr-value-color:light-dark(var(--rh-color-blue-60,#004d99),var(--rh-color-green-40,#87bb62));--_keyword-color:light-dark(var(--rh-color-blue-60,#004d99),var(--rh-color-purple-30,#b6a6e9));--_function-color:light-dark(var(--rh-color-red-60,#a60000),var(--rh-color-orange-40,#f5921b));--_class-name-color:light-dark(var(--rh-color-red-60,#a60000),var(--rh-color-yellow-40,#dca614));--_regex-color:light-dark(var(--rh-color-orange-60,#9e4a06),var(--rh-color-green-40,#87bb62));--_important-color:light-dark(var(--rh-color-orange-60,#9e4a06),var(--rh-color-purple-30,#b6a6e9));--_variable-color:light-dark(var(--rh-color-orange-60,#9e4a06),var(--rh-color-green-40,#87bb62));display:grid;place-items:center;grid-template-columns:auto min-content;grid-template-areas:"code actions" "expand expand";column-gap:var(--_code-main-spacer);padding-inline-start:var(--_code-main-spacer);padding-block-end:var(--_code-main-spacer);border-radius:var(--rh-border-radius-default,3px);background-color:var(--_code-background-color);color:var(--rh-color-text-primary);border:var(--rh-border-width-sm,1px) solid var(--rh-color-border-subtle);border-block-start-width:var(--rh-code-block-border-block-start-width,var(--rh-border-width-sm,1px));content-visibility:auto;contain-intrinsic-block-size:auto 193px;--_gradient:linear-gradient(var(--_gradient-angle,0deg),var(--_code-background-color) 0%,#0000 100%)}#container.isIntersecting,#container:not(.line-numbers):not(.isIntersecting){content-visibility:visible}#container.expandable{padding-block-end:0}#content,#prism-output,#sizers{display:block;font-family:var(--rh-font-family-code,RedHatMono,"Red Hat Mono","Courier New",Courier,monospace);z-index:1;place-self:start;grid-area:code}#content::slotted(:is(script,pre)),#prism-output,#sizers{display:inline;white-space:var(--_code-white-space,pre);word-wrap:var(--_code-word-wrap,initial);color:inherit}#content::slotted(:is(code[class*=language-],pre[class*=language-])){color:var(--_code-color);font-family:var(--rh-font-family-code,RedHatMono,"Red Hat Mono","Courier New",Courier,monospace);text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:var(--rh-line-height-code,1.5);tab-size:4;hyphens:none;background:#0000}:is(:host([highlighting=prerendered]) .wrap) #content::slotted(pre[class*=language-]){white-space:pre-wrap!important}#content::slotted(rh-tag){width:var(--rh-size-icon-06,64px)}#content-lines{display:grid;column-gap:var(--rh-space-lg,16px);grid-area:code;grid-template-areas:"lines code";grid-template-columns:min-content 1fr;grid-template-rows:1fr;position:relative;overflow-y:auto;margin-block-start:var(--_code-main-spacer);width:100%}#sizers{position:absolute;min-width:100%;width:100%;opacity:0;pointer-events:none;z-index:-10000;line-height:var(--rh-line-height-code,1.5)}#line-numbers{pointer-events:none;overflow-y:hidden;margin:0;grid-area:lines;list-style-type:none;padding-inline:0 var(--rh-space-md,8px);text-align:end;font-family:var(--rh-font-family-code,RedHatMono,"Red Hat Mono","Courier New",Courier,monospace);color:var(--rh-color-text-secondary);font-weight:var(--rh-font-weight-code-regular,400);border-inline-end:var(--rh-border-width-sm,1px) solid var(--rh-color-border-subtle)}#line-numbers li{line-height:var(--rh-line-height-code,1.5);display:block}#actions{display:flex;grid-area:actions;gap:var(--rh-space-md,8px);flex-flow:column;margin-block-start:var(--rh-space-lg,16px);margin-inline-end:var(--rh-space-lg,16px);z-index:2;place-self:start center;height:100%;position:relative;--_gradient-angle:270deg}#actions rh-tooltip{display:block;z-index:10000}#expand{--_code-secondary-spacer:var(--rh-space-md,8px);display:inline-flex;align-items:center;border:0;background:#0000;grid-area:expand;gap:var(--rh-space-md,8px);inset-block-end:var(--_code-secondary-spacer);margin-block:var(--_code-secondary-spacer);color:var(--rh-color-text-primary);font-family:var(--rh-font-family-body-text,RedHatText,"Red Hat Text",Helvetica,Arial,sans-serif);font-size:var(--rh-font-size-body-text-sm,.875rem);font-weight:var(--rh-font-weight-body-text-regular,400);line-height:var(--rh-line-height-body-text,1.5)}#expand svg{width:11px;height:7px;rotate:var(--_expand-toggle-rotate,180deg);transform:rotate .2s ease-in-out;color:var(--rh-color-icon-secondary)}#container.compact{--_code-main-spacer:var(--rh-space-lg,16px);--_code-secondary-spacer:var(--rh-space-sm,6px)}.resizable #content-lines{resize:vertical;overflow-x:scroll}.truncated #content-lines{max-height:calc(var(--rh-font-size-code-md, 1rem)*8)}.truncated #content-lines:before{content:"";display:block;position:sticky;z-index:2;inset-block-end:0;inset-inline:0;height:var(--rh-space-3xl,48px);pointer-events:none;grid-column:-1/1;background:var(--_gradient)}:host([line-numbers=hidden]) #content-lines{grid-template-areas:"code";grid-template-columns:1fr}:host([line-numbers=hidden]) #line-numbers{display:none}:not(.wrap) #actions:before{content:"";display:block;position:absolute;z-index:2;inset-block:0;inset-inline-start:calc(var(--rh-space-4xl, 64px)*-1);width:var(--rh-space-4xl,64px);pointer-events:none;background:var(--_gradient)}:not(.actions) #actions{margin:0}.wrap{--_code-white-space:pre-wrap;--_code-word-wrap:anywhere}[name=legend]::slotted(dl){display:grid;grid-template-columns:max-content auto;margin-block:var(--rh-space-lg,16px);gap:var(--rh-space-md,8px)}:host([highlighting=client]) #content::slotted(:is(script,pre)){display:none}`; /** * Returns a string with common indent stripped from each line. Useful for templating HTML * @param str indented string */ function dedent(str) { const stripped = str.replace(/^\n/, ''); const match = stripped.match(/^\s+/); const out = match ? stripped.replace(new RegExp(`^${match[0]}`, 'gm'), '') : str; return out.trim(); } const prismApplyPromises = new WeakMap(); export class RhCodeBlockCopyEvent extends Event { constructor( /** Text content to copy */ content) { super('copy', { bubbles: true, cancelable: true }); this.content = content; } } /** * A code block applies special formatting to sections of code. * * @alias code-block * * @summary Formats code strings within a container * @event {RhCodeBlockCopyEvent} copy - fired when the user requests to copy the code block text. * Modify the `event.content` field to change the copied text * (e.g. to remove a prompt from a shell command) */ let RhCodeBlock = RhCodeBlock_1 = class RhCodeBlock extends LitElement { constructor() { super(...arguments); _RhCodeBlock_instances.add(this); /** * Space- or comma-separated list of code block action buttons to display, containing either 'copy', 'wrap', or both. * 'copy' adds a button that copies the text content to the clipboard. 'wrap' adds a button that toggles line wrap. * * To override the default labels, e.g. for purposes of internationalization, use the * `action-label-copy` and `action-label-wrap` slots. Each slot may receive two elements, * one for the action's default state (e.g. "Copy to clipboard"), * and one for the actions alternative state, e.g. "Copied!". * The active-state element must have the attributes `hidden data-code-block-state="active"` * * @example html``` * <rh-code-block actions="copy wrap"> * <span slot="action-label-copy">Copy to Clipboard</span> * <span slot="action-label-copy" hidden data-code-block-state="active">Copied!</span> * <span slot="action-label-copy" hidden data-code-block-state="failed">Copy failed!</span> * <span slot="action-label-wrap">Toggle word wrap</span> * <span slot="action-label-wrap" hidden data-code-block-state="active">Toggle overflow</span> * </rh-code-block> * ``` */ this.actions = []; /** When set, the code block displays with compact spacing */ this.compact = false; /** When set, the code block source code will be dedented */ this.dedent = false; /** When set, the code block is resizable */ this.resizable = false; /** When set, the code block occupies it's full height, without scrolling */ this.fullHeight = false; /** When set, lines in the code snippet wrap */ this.wrap = false; this.copyButtonState = 'default'; _RhCodeBlock_logger.set(this, new Logger(this)); _RhCodeBlock_slots.set(this, new SlotController(this, null, 'action-label-copy', 'copy-failed', 'action-label-wrap', 'show-more', 'show-less', 'legend')); _RhCodeBlock_prismOutput.set(this, void 0); _RhCodeBlock_isIntersecting.set(this, false); _RhCodeBlock_ro.set(this, void 0); _RhCodeBlock_lines.set(this, []); _RhCodeBlock_lineHeights.set(this, []); } connectedCallback() { super.connectedCallback(); if (!isServer) { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_updateResizeObserver).call(this); } __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onSlotChange).call(this); } disconnectedCallback() { super.disconnectedCallback(); __classPrivateFieldGet(this, _RhCodeBlock_ro, "f")?.disconnect(); } render() { const { fullHeight, wrap, resizable, compact } = this; const lineNumbers = this.lineNumbers !== 'hidden'; const expandable = __classPrivateFieldGet(this, _RhCodeBlock_lines, "f").length > 5; const truncated = expandable && !fullHeight; const actions = !!this.actions.length; const isIntersecting = __classPrivateFieldGet(this, _RhCodeBlock_isIntersecting, "f") && this.lineNumbers !== 'hidden'; const actionCopyLabelledBy = this.copyButtonState === 'default' ? 'copy-to-clipboard-label' : this.copyButtonState === 'active' ? 'copied-label' : 'copy-failed-label'; return html ` <div id="container" class="${classMap({ actions, compact, expandable, fullHeight, isIntersecting, resizable, truncated, wrap, 'line-numbers': lineNumbers })}" @code-action="${__classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onCodeAction)}" @contentvisibilityautostatechange="${__classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onVisibilityChange)}"> <div id="content-lines" tabindex="${ifDefined((!fullHeight || undefined) && 0)}"> <div id="sizers" aria-hidden="true"></div> <ol id="line-numbers" inert aria-hidden="true">${__classPrivateFieldGet(this, _RhCodeBlock_lineHeights, "f").map((height, i) => html ` <li style="${styleMap({ height })}">${i + 1}</li>`)} </ol> <pre id="prism-output" class="language-${this.language}" ?hidden="${!__classPrivateFieldGet(this, _RhCodeBlock_prismOutput, "f")}">${__classPrivateFieldGet(this, _RhCodeBlock_prismOutput, "f")}</pre> <!-- A non-executable script tag containing the sample content. JavaScript samples should use the type \`text/sample-javascript\`. HTML samples containing script tags must escape the closing \`</script>\` tag. Can also be a \`<pre>\` tag. --> <slot id="content" ?hidden="${!!__classPrivateFieldGet(this, _RhCodeBlock_prismOutput, "f")}" @slotchange="${__classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onSlotChange)}"></slot> </div> <div id="actions" @click="${__classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onActionsClick)}" @keyup="${__classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onActionsKeyup)}"> ${!this.actions.includes('copy') ? '' : html ` <rh-tooltip silent> <!-- Tooltip content for the copy action button --> <slot slot="content" name="action-label-copy"> <span ?hidden="${this.copyButtonState !== 'default'}" id="copy-to-clipboard-label">Copy to Clipboard</span> <span ?hidden="${this.copyButtonState !== 'active'}" id="copied-label">Copied!</span> <span ?hidden="${this.copyButtonState !== 'failed'}" id="copy-failed-label">Copy failed!</span> </slot> <button id="action-copy" class="shadow-fab" data-code-block-action="copy" aria-labelledby="${actionCopyLabelledBy}"> ${RhCodeBlock_1.actionIcons.get('copy')} </button> </rh-tooltip>`} ${!this.actions.includes('wrap') ? '' : html ` <rh-tooltip silent> <!-- Tooltip content for the wrap action button --> <slot id="label-wrap" slot="content" name="action-label-wrap"> <span ?hidden="${this.wrap}">Toggle word wrap</span> <span ?hidden="${!this.wrap}" data-code-block-state="active">Toggle overflow</span> </slot> <button id="action-wrap" class="shadow-fab" data-code-block-action="wrap" aria-labelledby="label-wrap"> ${RhCodeBlock_1.actionIcons.get(this.wrap ? 'wrap-active' : 'wrap')} </button> </rh-tooltip> `} </div> <button id="expand" ?hidden="${!expandable}" aria-controls="content-lines" aria-expanded="${String(!!fullHeight)}" @click="${__classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onClickExpand)}" aria-labelledby="${this.fullHeight === true ? 'show-less-label' : 'show-more-label'}"> <span ?hidden="${this.fullHeight}" id="show-more-label"> <!-- text content for the expandable toggle button when the code block is collapsed. --> <slot name="show-more">Show more</slot> </span> <span ?hidden="${!this.fullHeight}" id="show-less-label"> <!-- text content for the expandable toggle button when the code block is expanded. --> <slot name="show-less">Show less</slot> </span> <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 11 7"> <path d="M4.919.239.242 4.847a.801.801 0 0 0 0 1.148l.778.766a.83.83 0 0 0 1.165 0L5.5 3.495 8.815 6.76a.83.83 0 0 0 1.165 0l.778-.766a.802.802 0 0 0 0-1.148L6.08.239a.826.826 0 0 0-1.162 0Z"/> </svg> </button> </div> <!-- \`<dl>\` element containing rh-badges in the \`<dt>\` and legend text in the \`<dd>\` elements --> <slot name="legend" ?hidden="${__classPrivateFieldGet(this, _RhCodeBlock_slots, "f").isEmpty('legend')}"></slot> `; } firstUpdated() { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLines).call(this); // After computing lines, also update line heights if visible __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLineNumbers).call(this); } updated(changed) { if (changed.has('wrap')) { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_wrapChanged).call(this); } if (changed.has('lineNumbers') && !isServer) { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_updateResizeObserver).call(this); } if (this.actions.length && !isServer) { import('@rhds/elements/rh-tooltip/rh-tooltip.js'); } } }; _RhCodeBlock_logger = new WeakMap(); _RhCodeBlock_slots = new WeakMap(); _RhCodeBlock_prismOutput = new WeakMap(); _RhCodeBlock_isIntersecting = new WeakMap(); _RhCodeBlock_ro = new WeakMap(); _RhCodeBlock_lines = new WeakMap(); _RhCodeBlock_lineHeights = new WeakMap(); _RhCodeBlock_instances = new WeakSet(); _RhCodeBlock_onSlotChange = async function _RhCodeBlock_onSlotChange() { switch (this.highlighting) { case 'client': await __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_highlightWithPrism).call(this); break; // TODO: if we ever support other tokenizers e.g. highlightjs, // dispatch here off of some supplemental attribute like `tokenizer="highlightjs"` case 'prerendered': await __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_applyPrismPrerenderedStyles).call(this); break; } await __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLines).call(this); // After computing lines, also update line heights if visible __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLineNumbers).call(this); }; _RhCodeBlock_applyPrismPrerenderedStyles = async function _RhCodeBlock_applyPrismPrerenderedStyles() { let root; if (!isServer && !prismApplyPromises.has((root = this.getRootNode()))) { if (root instanceof Document || root instanceof ShadowRoot) { prismApplyPromises.set(root, (async function () { const { preRenderedLightDomStyles: { styleSheet } } = await import('./prism.css.js'); root.adoptedStyleSheets = [...root.adoptedStyleSheets, styleSheet]; })()); } } }; _RhCodeBlock_highlightWithPrism = async function _RhCodeBlock_highlightWithPrism() { if (!isServer) { const { highlight, prismStyles } = await import('./prism.js'); const styleSheet = prismStyles instanceof CSSStyleSheet ? prismStyles : prismStyles.styleSheet; if (!this.shadowRoot.adoptedStyleSheets.includes(styleSheet)) { this.shadowRoot.adoptedStyleSheets = [ ...this.shadowRoot.adoptedStyleSheets, styleSheet, ]; } const scripts = this.querySelectorAll('script[type]:not([type="javascript"])'); const preprocess = this.dedent ? dedent : (x) => x; const textContent = preprocess(Array.from(scripts, x => x.textContent).join('')); __classPrivateFieldSet(this, _RhCodeBlock_prismOutput, await highlight(textContent, this.language), "f"); this.requestUpdate('#prismOutput', {}); await this.updateComplete; } }; _RhCodeBlock_onVisibilityChange = function _RhCodeBlock_onVisibilityChange(event) { // skipped = true means content is NOT being rendered (off-screen) // skipped = false means content IS being rendered (on/near screen) const { skipped } = event; const old = __classPrivateFieldGet(this, _RhCodeBlock_isIntersecting, "f"); __classPrivateFieldSet(this, _RhCodeBlock_isIntersecting, !skipped, "f"); if (old !== __classPrivateFieldGet(this, _RhCodeBlock_isIntersecting, "f")) { this.requestUpdate(); if (__classPrivateFieldGet(this, _RhCodeBlock_isIntersecting, "f") && this.lineNumbers !== 'hidden') { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLineNumbers).call(this); } } }; _RhCodeBlock_updateResizeObserver = function _RhCodeBlock_updateResizeObserver() { const shouldHaveObserver = this.wrap && this.lineNumbers !== 'hidden'; if (!shouldHaveObserver && __classPrivateFieldGet(this, _RhCodeBlock_ro, "f")) { // Clean up observer when not needed __classPrivateFieldGet(this, _RhCodeBlock_ro, "f").disconnect(); __classPrivateFieldSet(this, _RhCodeBlock_ro, undefined, "f"); } else if (shouldHaveObserver && !__classPrivateFieldGet(this, _RhCodeBlock_ro, "f")) { // Create observer only when both conditions are met __classPrivateFieldSet(this, _RhCodeBlock_ro, new ResizeObserver(() => __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLineNumbers).call(this)), "f"); __classPrivateFieldGet(this, _RhCodeBlock_ro, "f").observe(this); } }; _RhCodeBlock_wrapChanged = async function _RhCodeBlock_wrapChanged() { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_updateResizeObserver).call(this); await this.updateComplete; __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_computeLineNumbers).call(this); __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_setSlottedLabelState).call(this, 'action-label-wrap', this.wrap ? 'active' : undefined); }; _RhCodeBlock_setSlottedLabelState = function _RhCodeBlock_setSlottedLabelState(slotName, state) { if (__classPrivateFieldGet(this, _RhCodeBlock_slots, "f").hasSlotted(slotName)) { for (const el of __classPrivateFieldGet(this, _RhCodeBlock_slots, "f").getSlotted(slotName)) { if (el instanceof HTMLElement) { el.hidden = el.dataset.codeBlockState !== state; } } } }; _RhCodeBlock_getSlottedCodeElements = function _RhCodeBlock_getSlottedCodeElements() { const slot = this.shadowRoot?.getElementById('content'); return slot.assignedElements().flatMap(x => x instanceof HTMLScriptElement || x instanceof HTMLPreElement ? [x] : []); }; _RhCodeBlock_computeLines = /** * Calculate the number of lines in the code block */ async function _RhCodeBlock_computeLines() { await this.updateComplete; const codes = __classPrivateFieldGet(this, _RhCodeBlock_prismOutput, "f") ? [this.shadowRoot?.getElementById('prism-output')].filter(x => !!x) : __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_getSlottedCodeElements).call(this); __classPrivateFieldSet(this, _RhCodeBlock_lines, codes.flatMap(element => element.textContent?.split(/\n(?!$)/g) ?? []), "f"); this.requestUpdate(); }; _RhCodeBlock_computeLineNumbers = /** * Calculate line heights for line numbers display * @license MIT * Portions copyright prism.js authors (MIT license) */ async function _RhCodeBlock_computeLineNumbers() { if (!__classPrivateFieldGet(this, _RhCodeBlock_isIntersecting, "f") || this.lineNumbers === 'hidden') { return; } await this.updateComplete; const codes = __classPrivateFieldGet(this, _RhCodeBlock_prismOutput, "f") ? [this.shadowRoot?.getElementById('prism-output')].filter(x => !!x) : __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_getSlottedCodeElements).call(this); const infos = codes.map(element => { const codeElement = __classPrivateFieldGet(this, _RhCodeBlock_prismOutput, "f") ? element.querySelector('code') : element; if (codeElement) { const sizer = document.createElement('span'); sizer.className = 'sizer'; sizer.innerText = '0'; sizer.style.display = 'block'; this.shadowRoot?.getElementById('sizers')?.appendChild(sizer); return { lines: element.textContent?.split(/\n(?!$)/g) ?? [], lineHeights: [], sizer, oneLinerHeight: sizer.getBoundingClientRect().height, }; } }).filter(x => !!x); for (const { lines, lineHeights, sizer, oneLinerHeight } of infos) { lineHeights[lines.length - 1] = undefined; // why? lines.forEach((line, i) => { if (line.length > 1) { const e = sizer.appendChild(document.createElement('span')); e.style.display = 'block'; e.textContent = line; } else { lineHeights[i] = oneLinerHeight; } }); } for (const { sizer, lineHeights } of infos) { let childIndex = 0; for (let i = 0; i < lineHeights.length; i++) { if (lineHeights[i] === undefined) { lineHeights[i] = sizer.children[childIndex++].getBoundingClientRect()?.height ?? 0; } } sizer.remove(); } __classPrivateFieldSet(this, _RhCodeBlock_lineHeights, infos.flatMap(x => x.lineHeights?.map(y => `${y ?? x.oneLinerHeight}px`)), "f"); this.requestUpdate('#linesNumbers', 0); }; _RhCodeBlock_onActionsClick = function _RhCodeBlock_onActionsClick(event) { __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onCodeAction).call(this, event); }; _RhCodeBlock_onActionsKeyup = function _RhCodeBlock_onActionsKeyup(event) { switch (event.key) { case 'Enter': return; case ' ': event.preventDefault(); __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_onCodeAction).call(this, event); } }; _RhCodeBlock_onCodeAction = function _RhCodeBlock_onCodeAction(event) { const el = event.composedPath().find((x) => x instanceof HTMLElement && !!x.dataset.codeBlockAction); if (el) { switch (el.dataset.codeBlockAction) { case 'copy': return __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_copy).call(this); case 'wrap': this.wrap = !this.wrap; this.requestUpdate(); return; } } }; _RhCodeBlock_onClickExpand = function _RhCodeBlock_onClickExpand() { this.fullHeight = !this.fullHeight; }; _RhCodeBlock_preCopy = function _RhCodeBlock_preCopy() { let content; if (this.highlighting === 'prerendered') { content = Array.from(this.querySelectorAll('pre'), x => x?.textContent ?? '').join(''); } else { content = Array.from(this.querySelectorAll('script'), x => x.textContent).join(''); } const event = new RhCodeBlockCopyEvent(content); if (!this.dispatchEvent(event) || event.defaultPrevented) { throw new Error('copy cancelled'); } return event.content; }; _RhCodeBlock_copy = async function _RhCodeBlock_copy() { const slot = this.shadowRoot?.querySelector('slot[name="action-label-copy"]'); const tooltip = slot?.closest('rh-tooltip'); if (!tooltip) { return; } try { tooltip.hide(); const content = __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_preCopy).call(this); await navigator.clipboard.writeText(content); this.copyButtonState = 'active'; __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_setSlottedLabelState).call(this, 'action-label-copy', 'active'); } catch (error) { __classPrivateFieldGet(this, _RhCodeBlock_logger, "f").error(error); this.copyButtonState = 'failed'; __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_setSlottedLabelState).call(this, 'action-label-copy', 'failed'); } tooltip.show(); await new Promise(r => setTimeout(r, 5000)); tooltip.hide(); this.copyButtonState = 'default'; __classPrivateFieldGet(this, _RhCodeBlock_instances, "m", _RhCodeBlock_setSlottedLabelState).call(this, 'action-label-copy', undefined); tooltip.show(); }; RhCodeBlock.actionIcons = new Map([ ['wrap', html ` <svg xmlns="http://www.w3.org/2000/svg" role="presentation" fill="currentColor" viewBox="0 0 20 20"> <path d="M19 0c.313.039.781-.077 1 .057V20c-.313-.039-.781.077-1-.057V0ZM10.82 4.992C9.877 4.996 8.31 5.57 8.174 6c1.21.03 2.432-.073 3.635.08 2.181.383 3.677 2.796 3.066 4.922-.41 1.753-2.108 2.995-3.877 3.014L11 14H5.207l2.682-2.682-.707-.707L3.293 14.5l3.889 3.889.707-.707L5.207 15h5.736l.004-.008c1.444.005 2.896-.59 3.832-1.722 1.65-1.82 1.612-4.85-.08-6.63A5 5 0 0 0 11 5a1.948 1.948 0 0 0-.18-.008z"/> <path d="M4 5h7c-.039.313.077.781-.057 1H4V5ZM0 0c.313.039.781-.077 1 .057V20c-.313-.039-.781.077-1-.057V0Z"/> </svg> `], ['wrap-active', html ` <svg xmlns="http://www.w3.org/2000/svg" role="presentation" fill="none" viewBox="0 0 21 20"> <path fill="currentColor" d="M12 13h1v7h-1zM12 0h1v7h-1z"/> <path stroke="currentColor" d="M16.465 6.464 20 10l-3.535 3.536"/> <path fill="currentColor" d="M3 9.5h17v1H3zM0 0h1v20H0z"/> </svg> `], ['copy', html ` <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 20 20"> <path fill="currentColor" d="M12 0H2C.9 0 0 .9 0 2v10h1V2c0-.6.4-1 1-1h10V0z"/> <path fill="currentColor" d="M18 20H8c-1.1 0-2-.9-2-2V8c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2v10c0 1.1-.9 2-2 2zM8 7c-.6 0-1 .4-1 1v10c0 .6.4 1 1 1h10c.6 0 1-.4 1-1V8c0-.6-.4-1-1-1H8z"/> </svg> `], ]); RhCodeBlock.styles = [style]; __decorate([ property({ reflect: true, converter: { fromAttribute(value) { return ((value ?? '').split(/\s+|,/) ?? []).map(x => x.trim()).filter(Boolean); }, toAttribute(value) { return Array.isArray(value) ? value.join(' ') : ''; }, }, }) ], RhCodeBlock.prototype, "actions", void 0); __decorate([ property() ], RhCodeBlock.prototype, "highlighting", void 0); __decorate([ property() ], RhCodeBlock.prototype, "language", void 0); __decorate([ property({ type: Boolean, reflect: true }) ], RhCodeBlock.prototype, "compact", void 0); __decorate([ property({ type: Boolean, reflect: true }) ], RhCodeBlock.prototype, "dedent", void 0); __decorate([ property({ type: Boolean, reflect: true }) ], RhCodeBlock.prototype, "resizable", void 0); __decorate([ property({ type: Boolean, reflect: true, attribute: 'full-height' }) ], RhCodeBlock.prototype, "fullHeight", void 0); __decorate([ property({ type: Boolean }) ], RhCodeBlock.prototype, "wrap", void 0); __decorate([ property({ reflect: true, attribute: 'line-numbers' }) ], RhCodeBlock.prototype, "lineNumbers", void 0); __decorate([ state() ], RhCodeBlock.prototype, "copyButtonState", void 0); RhCodeBlock = RhCodeBlock_1 = __decorate([ customElement('rh-code-block'), themable ], RhCodeBlock); export { RhCodeBlock }; //# sourceMappingURL=rh-code-block.js.map