Copy environment

Detail Demo

<div class="detail-demo  " data-initial="30">
    <div class="detail-demo__line-wrapper">
        <div class="detail-demo__text" contentEditable="true"></div>
        <div class="detail-demo__single-line">
            Väike mölder hüppas üle rongi
        </div>
    </div>
</div>
{% set lineHeight %}
    {% if data.customLineHeight %}style="line-height: {{ data.lineHeight }}em"{% endif %}
{% endset %}

<div class="detail-demo {{ class }} {{ modifier }}" data-initial="{{ data.initialSize }}">
    <div class="detail-demo__line-wrapper">
        <div class="detail-demo__text" contentEditable="true" {{ lineHeight }}></div>
        <div class="detail-demo__single-line" {{ lineHeight }}>
            {{ data.placeholder }}
        </div>
    </div>
</div>
{
  "language": "en-US",
  "data": {
    "placeholder": "Väike mölder hüppas üle rongi",
    "initialSize": 30,
    "lineHeight": "normal"
  }
}
  • Content:
    .detail-demo {
        position: relative;
        display: flex;
        flex-direction: column;
        justify-content: center;
        cursor: text;
        overflow: hidden;
        padding: 16px;
        font-size: 35px;
    
        @include bp(sm-min) {
            font-size: 50px;
            padding: 32px;
        }
    }
    
    .detail-demo__single-line {
        position: absolute;
        pointer-events: none;
        line-height: normal;
        opacity: .2;
        top: 0;
    
        .detail-demo__text:focus + & {
            display: none;
        }
    }
    
    .detail-demo__line-wrapper {
        position: relative;
        max-height: 100%;
        overflow: hidden;
    }
    
    .detail-demo__text {
        line-height: normal;
    }
    
  • URL: /components/raw/detail-demo/detail-demo.scss
  • Filesystem Path: src/patterns/components/detail-demo/detail-demo.scss
  • Size: 627 Bytes
  • Content:
    import './detail-demo.scss';
    import Component from '@component';
    
    interface IDetailDemoSettings {
        textClass: string;
        singleLineClass: string;
        lineWrapperClass: string;
        initial: number;
    }
    
    export default class DetailDemo extends Component {
        static initSelector: string = '.detail-demo';
    
        settings: IDetailDemoSettings;
    
        text: JQuery;
        singleLine: JQuery;
        lines: JQuery;
    
        constructor(element: HTMLElement) {
            super(element);
    
            this.settings = $.extend({
                initial: null,
                lineWrapperClass: 'detail-demo__line-wrapper',
                singleLineClass: 'detail-demo__single-line',
                textClass: 'detail-demo__text',
            }, this.element.data());
    
            this.text = this.element.find('.' + this.settings.textClass);
            this.lines = this.element.find('.' + this.settings.lineWrapperClass);
            this.element.css('font-size', this.settings.initial);
            this.singleLine = this.element.find('.' + this.settings.singleLineClass);
    
            this.init();
        }
    
        init(): void {
            this.element.on('click', this.clickHandler.bind(this));
            this.text.on('blur', this.unclickHandler.bind(this));
            this.text.on('input', this.inputHandler.bind(this));
            this.text[0].addEventListener('paste', this.pasteHandler.bind(this));
            requestAnimationFrame(this.inputHandler.bind(this));
    
            const observer: MutationObserver = new MutationObserver((mutations: MutationRecord[]) => {
                mutations.forEach((): void => {
                    this.updateHeight();
                });
            });
    
            observer.observe(this.element[0], { attributeFilter: ['style'], attributes: true });
        }
    
        pasteHandler(event: ClipboardEvent): void {
            event.preventDefault();
            const paste: string = event.clipboardData.getData('text/plain');
            const range: Range = document.createRange();
    
            this.text.append(paste);
            range.selectNodeContents(this.text[0]);
            range.collapse(false);
    
            const selection: Selection = window.getSelection();
    
            selection.removeAllRanges();
            selection.addRange(range);
    
            this.inputHandler();
        }
    
        inputHandler(): void {
            this.updateHeight();
            this.updateHintVisibility();
        }
    
        updateHintVisibility(): void {
            if (this.text.html().length === 0) {
                this.singleLine.css('visibility', 'visible');
            } else {
                this.singleLine.css('visibility', 'hidden');
            }
        }
    
        updateHeight(): void {
            const demoHeight: number = this.element[0].getBoundingClientRect().height - parseInt(this.element.css('padding')) * 2;
            const singleLineHeight: number = this.singleLine.height();
            const maxLines: number = Math.max(1, Math.floor(demoHeight / singleLineHeight));
    
            this.lines.css('height', Math.min(maxLines * singleLineHeight, this.text[0].getBoundingClientRect().height));
        }
    
        unclickHandler(): void {
            this.text.attr('contenteditable', 'false');
        }
    
        clickHandler(): void {
            this.text.attr('contenteditable', 'true');
            this.text.trigger('focus');
        }
    }
    
  • URL: /components/raw/detail-demo/detail-demo.ts
  • Filesystem Path: src/patterns/components/detail-demo/detail-demo.ts
  • Size: 3.2 KB
  • Handle: @detail-demo--default
  • Filesystem Path: src/patterns/components/detail-demo/detail-demo.twig
  • Referenced by (1): @detail-preview