carbon-components-angular
Version:
Next generation components
523 lines (512 loc) • 21.1 kB
JavaScript
import * as i0 from '@angular/core';
import { Component, HostBinding, Input, ViewChild, NgModule } from '@angular/core';
import * as i4 from 'carbon-components-angular/button';
import { BaseIconButton, ButtonModule } from 'carbon-components-angular/button';
import * as i1 from 'carbon-components-angular/i18n';
import { I18nModule } from 'carbon-components-angular/i18n';
import * as i2 from 'carbon-components-angular/utils';
import { UtilsModule } from 'carbon-components-angular/utils';
import * as i3 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i5 from 'carbon-components-angular/icon';
import { IconModule } from 'carbon-components-angular/icon';
var SnippetType;
(function (SnippetType) {
SnippetType["single"] = "single";
SnippetType["multi"] = "multi";
SnippetType["inline"] = "inline";
})(SnippetType || (SnippetType = {}));
/**
* Get started with importing the module:
*
* ```typescript
* import { CodeSnippetModule } from 'carbon-components-angular';
* ```
*
* ```html
* <cds-code-snippet>Code</cds-code-snippet>
* ```
*
* [See demo](../../?path=/story/components-code-snippet--basic)
*/
class CodeSnippet extends BaseIconButton {
/**
* Creates an instance of CodeSnippet.
*/
constructor(i18n, eventService) {
super();
this.i18n = i18n;
this.eventService = eventService;
this.rowHeightInPixel = 16;
/**
* It can be `"single"`, `"multi"` or `"inline"`
*/
this.display = SnippetType.single;
this.translations = this.i18n.get().CODE_SNIPPET;
/**
* Set to `true` to hide copy button
*/
this.hideCopyButton = false;
/**
* Set to `true` to disable the code snippet
*/
this.disabled = false;
/**
* Specify the max number of rows to show when collapsed
* Default is `15`
*/
this.maxCollapsedNumberOfRows = 15;
/**
* Specify the min number of rows to show when collapsed
* Default is `3`
*/
this.minCollapsedNumberOfRows = 3;
/**
* Specify the max number of rows to show when expanded
* Default is `0`, hence all content will be visible when expanded
*/
this.maxExpandedNumberOfRows = 0;
/**
* Specify the min number of rows to show when expanded
* Default is `16`, hence height of expanded row will be 16 * rowHeightInPixel (16) = 256px
*/
this.minExpandedNumberOfRows = 16;
/**
* Set to `true` to wrap the text
*/
this.wrapText = false;
/**
* @deprecated since v5 - Use `cdsLayer` directive instead
* Set to `"light"` to apply the light style
*/
this.theme = "dark";
/**
* Text displayed in the tooltip when user clicks button to copy code.
*/
this.feedbackText = this.translations.COPIED;
/**
* Time in miliseconds to keep the feedback tooltip displayed.
* Defaults to 2 seconds
*/
this.feedbackTimeout = 2000;
this.expanded = false;
this.skeleton = false;
this.styles = {};
this.showFeedback = false;
this.animating = false;
this.hasExpandButton = null;
this.isExpandable = false;
this.hasRightOverflow = false;
this.hasRight = false;
this.hasLeft = false;
this.dropShadow = false;
}
get snippetClass() {
return this.display !== SnippetType.inline;
}
get snippetSingleClass() {
return this.display === SnippetType.single;
}
get snippetMultiClass() {
return this.display === SnippetType.multi;
}
get snippetDisabledClass() {
return this.display !== "inline" && this.disabled;
}
get snippetInlineLightClass() {
return this.theme === "light";
}
handleScroll() {
if (this.skeleton) {
return;
}
let ref;
switch (this.display) {
case "multi":
ref = this.codeContent.nativeElement;
break;
case "single":
ref = this.codeContainer.nativeElement;
break;
default:
return;
}
if (ref) {
const { scrollWidth, clientWidth, scrollLeft } = ref;
const horizontalOverflow = scrollWidth > clientWidth;
this.hasLeft = horizontalOverflow && !!scrollLeft;
this.hasRight = horizontalOverflow && scrollLeft + clientWidth !== scrollWidth;
}
}
toggleSnippetExpansion() {
this.expanded = !this.expanded;
this.calculateContainerHeight();
}
onCopyButtonClicked() {
if (!this.disabled) {
window.navigator.clipboard
.writeText(this.code.nativeElement.innerText || this.code.nativeElement.textContent).then(() => {
this.showFeedback = true;
this.animating = true;
setTimeout(() => {
this.showFeedback = false;
this.animating = false;
}, this.feedbackTimeout);
});
}
}
ngOnInit() {
this.calculateContainerHeight();
}
ngAfterViewInit() {
this.canExpand();
this.handleScroll();
if (window) {
this.eventService.on(window, "resize", () => {
this.canExpand();
this.handleScroll();
});
}
}
calculateContainerHeight() {
if (this.display === "multi" && !this.skeleton) {
this.styles = {};
if (this.expanded) {
if (this.maxExpandedNumberOfRows > 0) {
this.styles["max-height"] = `${this.maxExpandedNumberOfRows * this.rowHeightInPixel}px`;
}
if (this.minExpandedNumberOfRows > 0) {
this.styles["min-height"] = `${this.minExpandedNumberOfRows * this.rowHeightInPixel}px`;
}
}
else {
if (this.maxCollapsedNumberOfRows > 0) {
this.styles["max-height"] = `${this.maxCollapsedNumberOfRows * this.rowHeightInPixel}px`;
}
if (this.minCollapsedNumberOfRows > 0) {
this.styles["min-height"] = `${this.minCollapsedNumberOfRows * this.rowHeightInPixel}px`;
}
}
}
}
canExpand() {
if (this.display === "multi" && !this.skeleton) {
const height = this.codeContent.nativeElement.getBoundingClientRect().height;
if (this.maxCollapsedNumberOfRows > 0 &&
(this.maxExpandedNumberOfRows <= 0 ||
this.maxExpandedNumberOfRows > this.maxCollapsedNumberOfRows) &&
height > this.maxCollapsedNumberOfRows * this.rowHeightInPixel) {
this.isExpandable = true;
}
else {
this.isExpandable = false;
}
if (this.expanded &&
this.minExpandedNumberOfRows > 0 &&
height <= this.minExpandedNumberOfRows * this.rowHeightInPixel) {
this.isExpandable = false;
}
}
}
}
CodeSnippet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippet, deps: [{ token: i1.I18n }, { token: i2.EventService }], target: i0.ɵɵFactoryTarget.Component });
CodeSnippet.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CodeSnippet, selector: "cds-code-snippet, ibm-code-snippet", inputs: { display: "display", translations: "translations", copyButtonDescription: "copyButtonDescription", hideCopyButton: "hideCopyButton", disabled: "disabled", maxCollapsedNumberOfRows: "maxCollapsedNumberOfRows", minCollapsedNumberOfRows: "minCollapsedNumberOfRows", maxExpandedNumberOfRows: "maxExpandedNumberOfRows", minExpandedNumberOfRows: "minExpandedNumberOfRows", wrapText: "wrapText", theme: "theme", feedbackText: "feedbackText", feedbackTimeout: "feedbackTimeout", expanded: "expanded", skeleton: "skeleton" }, host: { properties: { "class.cds--snippet": "this.snippetClass", "class.cds--snippet--single": "this.snippetSingleClass", "class.cds--snippet--multi": "this.snippetMultiClass", "class.cds--snippet--disabled": "this.snippetDisabledClass", "class.cds--snippet--light": "this.snippetInlineLightClass", "class.cds--snippet--wraptext": "this.wrapText", "class.cds--snippet--expand": "this.expanded", "class.cds--skeleton": "this.skeleton" } }, viewQueries: [{ propertyName: "code", first: true, predicate: ["code"], descendants: true }, { propertyName: "codeContent", first: true, predicate: ["codeContent"], descendants: true }, { propertyName: "codeContainer", first: true, predicate: ["codeContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
<ng-container *ngIf="display === 'inline'; else notInline">
<ng-container *ngIf="!hideCopyButton; else noBtnInline">
<ng-container *ngTemplateOutlet="buttonTemplate"></ng-container>
</ng-container>
<ng-template #noBtnInline>
<span
class="cds--snippet cds--snippet--inline cds--snippet--no-copy"
[ngClass]="{
'cds--snippet--light': theme === 'light'
}">
<code #code>
<ng-container *ngTemplateOutlet="codeTemplate"></ng-container>
</code>
</span>
</ng-template>
</ng-container>
<ng-template #notInline>
<div
#codeContainer
class="cds--snippet-container"
[attr.aria-label]="translations.CODE_SNIPPET_TEXT"
[attr.tabindex]="display === 'single' && !disabled ? '0' : null"
[attr.role]="display==='single' ? 'textarea' : null"
[ngStyle]="styles"
(scroll)="(display === 'single' ? handleScroll() : null)">
<ng-container *ngIf="skeleton">
<span *ngIf="display === 'single'; else multiSkeleton"></span>
<ng-template #multiSkeleton>
<span></span>
<span></span>
<span></span>
</ng-template>
</ng-container>
<pre
#codeContent
*ngIf="!skeleton"
(scroll)="(display === 'multi' ? handleScroll() : null)"><code #code><ng-container *ngTemplateOutlet="codeTemplate"></ng-container></code></pre>
</div>
<div *ngIf="hasLeft" class="cds--snippet__overflow-indicator--left"></div>
<div *ngIf="hasRight" class="cds--snippet__overflow-indicator--right"></div>
<ng-container *ngIf="!hideCopyButton;">
<ng-container *ngTemplateOutlet="buttonTemplate"></ng-container>
</ng-container>
<button
*ngIf="isExpandable"
class="cds--btn cds--btn--ghost cds--btn--sm cds--snippet-btn--expand"
(click)="toggleSnippetExpansion()"
type="button">
<span class="cds--snippet-btn--text">{{expanded ? translations.SHOW_LESS : translations.SHOW_MORE}}</span>
<svg cdsIcon="chevron--down" size="16" class="cds--icon-chevron--down" [attr.aria-label]="translations.SHOW_MORE_ICON"></svg>
</button>
</ng-template>
<ng-template #buttonTemplate>
<cds-icon-button
*ngIf="!skeleton"
[description]="showFeedback ? feedbackText : copyButtonDescription"
[align]="align"
[dropShadow]="dropShadow"
[caret]="caret"
[highContrast]="highContrast"
[isOpen]="isOpen"
[enterDelayMs]="enterDelayMs"
[leaveDelayMs]="leaveDelayMs"
type="button"
kind="primary"
size="md"
(click)="onCopyButtonClicked($event)"
[buttonNgClass]="{
'cds--snippet--light': theme === 'light',
'cds--snippet--inline': display === 'inline',
'cds--btn--icon-only': display !== 'inline',
'cds--copy-btn': display !== 'inline',
'cds--copy-btn--animating': animating,
'cds--copy-btn--fade-in': showFeedback,
'cds--copy-btn--fade-out': !showFeedback && animating,
'cds--snippet cds--copy': true
}"
[buttonAttributes]="{
'aria-label': translations.COPY_CODE,
'aria-live': 'polite',
'tabindex': '0'
}">
<ng-container *ngIf="display === 'inline'">
<code #code>
<ng-container *ngTemplateOutlet="codeTemplate"></ng-container>
</code>
</ng-container>
<ng-container *ngIf="display !== 'inline'">
<svg cdsIcon="copy" size="16" class="cds--snippet__icon"></svg>
</ng-container>
</cds-icon-button>
</ng-template>
<ng-template #codeTemplate>
<ng-content></ng-content>
</ng-template>
`, isInline: true, dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i4.IconButton, selector: "cds-icon-button, ibm-icon-button", inputs: ["buttonNgClass", "buttonAttributes", "buttonId", "kind", "size", "type", "isExpressive", "disabled", "description"], outputs: ["click", "focus", "blur", "tooltipClick"] }, { kind: "directive", type: i5.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippet, decorators: [{
type: Component,
args: [{
selector: "cds-code-snippet, ibm-code-snippet",
template: `
<ng-container *ngIf="display === 'inline'; else notInline">
<ng-container *ngIf="!hideCopyButton; else noBtnInline">
<ng-container *ngTemplateOutlet="buttonTemplate"></ng-container>
</ng-container>
<ng-template #noBtnInline>
<span
class="cds--snippet cds--snippet--inline cds--snippet--no-copy"
[ngClass]="{
'cds--snippet--light': theme === 'light'
}">
<code #code>
<ng-container *ngTemplateOutlet="codeTemplate"></ng-container>
</code>
</span>
</ng-template>
</ng-container>
<ng-template #notInline>
<div
#codeContainer
class="cds--snippet-container"
[attr.aria-label]="translations.CODE_SNIPPET_TEXT"
[attr.tabindex]="display === 'single' && !disabled ? '0' : null"
[attr.role]="display==='single' ? 'textarea' : null"
[ngStyle]="styles"
(scroll)="(display === 'single' ? handleScroll() : null)">
<ng-container *ngIf="skeleton">
<span *ngIf="display === 'single'; else multiSkeleton"></span>
<ng-template #multiSkeleton>
<span></span>
<span></span>
<span></span>
</ng-template>
</ng-container>
<pre
#codeContent
*ngIf="!skeleton"
(scroll)="(display === 'multi' ? handleScroll() : null)"><code #code><ng-container *ngTemplateOutlet="codeTemplate"></ng-container></code></pre>
</div>
<div *ngIf="hasLeft" class="cds--snippet__overflow-indicator--left"></div>
<div *ngIf="hasRight" class="cds--snippet__overflow-indicator--right"></div>
<ng-container *ngIf="!hideCopyButton;">
<ng-container *ngTemplateOutlet="buttonTemplate"></ng-container>
</ng-container>
<button
*ngIf="isExpandable"
class="cds--btn cds--btn--ghost cds--btn--sm cds--snippet-btn--expand"
(click)="toggleSnippetExpansion()"
type="button">
<span class="cds--snippet-btn--text">{{expanded ? translations.SHOW_LESS : translations.SHOW_MORE}}</span>
<svg cdsIcon="chevron--down" size="16" class="cds--icon-chevron--down" [attr.aria-label]="translations.SHOW_MORE_ICON"></svg>
</button>
</ng-template>
<ng-template #buttonTemplate>
<cds-icon-button
*ngIf="!skeleton"
[description]="showFeedback ? feedbackText : copyButtonDescription"
[align]="align"
[dropShadow]="dropShadow"
[caret]="caret"
[highContrast]="highContrast"
[isOpen]="isOpen"
[enterDelayMs]="enterDelayMs"
[leaveDelayMs]="leaveDelayMs"
type="button"
kind="primary"
size="md"
(click)="onCopyButtonClicked($event)"
[buttonNgClass]="{
'cds--snippet--light': theme === 'light',
'cds--snippet--inline': display === 'inline',
'cds--btn--icon-only': display !== 'inline',
'cds--copy-btn': display !== 'inline',
'cds--copy-btn--animating': animating,
'cds--copy-btn--fade-in': showFeedback,
'cds--copy-btn--fade-out': !showFeedback && animating,
'cds--snippet cds--copy': true
}"
[buttonAttributes]="{
'aria-label': translations.COPY_CODE,
'aria-live': 'polite',
'tabindex': '0'
}">
<ng-container *ngIf="display === 'inline'">
<code #code>
<ng-container *ngTemplateOutlet="codeTemplate"></ng-container>
</code>
</ng-container>
<ng-container *ngIf="display !== 'inline'">
<svg cdsIcon="copy" size="16" class="cds--snippet__icon"></svg>
</ng-container>
</cds-icon-button>
</ng-template>
<ng-template #codeTemplate>
<ng-content></ng-content>
</ng-template>
`
}]
}], ctorParameters: function () { return [{ type: i1.I18n }, { type: i2.EventService }]; }, propDecorators: { snippetClass: [{
type: HostBinding,
args: ["class.cds--snippet"]
}], snippetSingleClass: [{
type: HostBinding,
args: ["class.cds--snippet--single"]
}], snippetMultiClass: [{
type: HostBinding,
args: ["class.cds--snippet--multi"]
}], snippetDisabledClass: [{
type: HostBinding,
args: ["class.cds--snippet--disabled"]
}], snippetInlineLightClass: [{
type: HostBinding,
args: ["class.cds--snippet--light"]
}], display: [{
type: Input
}], translations: [{
type: Input
}], copyButtonDescription: [{
type: Input
}], hideCopyButton: [{
type: Input
}], disabled: [{
type: Input
}], maxCollapsedNumberOfRows: [{
type: Input
}], minCollapsedNumberOfRows: [{
type: Input
}], maxExpandedNumberOfRows: [{
type: Input
}], minExpandedNumberOfRows: [{
type: Input
}], wrapText: [{
type: HostBinding,
args: ["class.cds--snippet--wraptext"]
}, {
type: Input
}], theme: [{
type: Input
}], feedbackText: [{
type: Input
}], feedbackTimeout: [{
type: Input
}], expanded: [{
type: HostBinding,
args: ["class.cds--snippet--expand"]
}, {
type: Input
}], skeleton: [{
type: HostBinding,
args: ["class.cds--skeleton"]
}, {
type: Input
}], code: [{
type: ViewChild,
args: ["code"]
}], codeContent: [{
type: ViewChild,
args: ["codeContent"]
}], codeContainer: [{
type: ViewChild,
args: ["codeContainer"]
}] } });
// modules
class CodeSnippetModule {
}
CodeSnippetModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippetModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
CodeSnippetModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippetModule, declarations: [CodeSnippet], imports: [CommonModule,
ButtonModule,
I18nModule,
UtilsModule,
IconModule], exports: [CodeSnippet] });
CodeSnippetModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippetModule, imports: [CommonModule,
ButtonModule,
I18nModule,
UtilsModule,
IconModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippetModule, decorators: [{
type: NgModule,
args: [{
declarations: [
CodeSnippet
],
exports: [
CodeSnippet
],
imports: [
CommonModule,
ButtonModule,
I18nModule,
UtilsModule,
IconModule
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { CodeSnippet, CodeSnippetModule, SnippetType };
//# sourceMappingURL=carbon-components-angular-code-snippet.mjs.map