TOGGLER-USAGE (Veams Components )

src/app/shared/components/toggler/templates

Demo Section

Each variation will be presented in the following section.

Default

Lorem ipsum dolor sit amet, consectetur adipisicing elit. A culpa deleniti distinctio eligendi enim explicabo, incidunt laborum laudantium magnam minus mollitia, perspiciatis porro quibusdam quis ratione reiciendis sapiente temporibus vel. Lorem ipsum dolor sit amet, consectetur adipisicing elit. A accusamus commodi corporis dicta excepturi, harum id, magnam maxime minima molestias nam nostrum perspiciatis possimus quaerat quis rerum suscipit ut, voluptate. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias aliquam aperiam consectetur culpa dolor dolorem esse in, libero magnam maiores, maxime perspiciatis quasi quod quos ratione sed tempore tenetur totam.


Readme

Toggler

Represents a simple toggler with global event binding.


Requirements


Installation

veams install component toggler
veams -i c toggler

Fields

toggler.hbs

Settings

Parameter Type Default Description
settings.togglerClasses String '' Modifier classes for component
settings.togglerContextClasses String 'default' Context class of component
settings.togglerJsOptions Object null Options object which gets stringified
settings.togglerJsModule Boolean false Specify if component is a Javascript module or not
settings.togglerJsModuleWithContext String '' Reference to specific Javascript module toggler context
settings.togglerId String '' Id to reference specific toggler component instance
settings.attributes Array [] List of attributes that consist of name value pairs

Content

Parameter Type Description
content.togglerField String Add description

JavaScript Options

The module gives you the possibility to override default options:

Option Type Default Description
classes.calculating String 'is-calculating' Class used to display calculating state
classes.close String 'is-closed' Class set while toggler is closed
classes.open String 'is-open' Class set while toggler is open
context Boolean false Context property that gets passed to toggler open event
dataMaxAttr String 'data-js-height' Dynamic max height attribute
globalEvent String '' Reference to global event that when triggered calls toggle method
globalEventId String '' Compare toggler’s globaleventid with the globaleventid of the object that triggered the toggle method to determine if toggle should be run or aborted
setOverflow Boolean false Specify if overflow should be set or not
toggleTabindexElems String '' Selector that targets elements to toggle tab-index

SASS

Variables

There are multiple variables which you can change:

Variable Value Description
$toggler-animation-duration-std 200ms Standard animation duration for toggler
$toggler-animation-easing-std ease-in-out Standard easing function

Templates

toggler-usage.hbs

<ul>
	<li>
		<a href="#" onclick="Veams.Vent.publish(Veams.EVENTS.toggler.toggle, {isActive: true})">Open the content</a>
	</li>
	<li>
		<a href="#" onclick="Veams.Vent.publish(Veams.EVENTS.toggler.toggle, {isActive: false})">Close the content</a>
	</li>
</ul>

{{! wrapWith START: Slider }}
{{#wrapWith "toggler" settings=this.settings content=this.content}}
	<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A culpa deleniti distinctio eligendi enim explicabo,
		incidunt laborum laudantium magnam minus mollitia, perspiciatis porro quibusdam quis ratione reiciendis sapiente
		temporibus vel. Lorem ipsum dolor sit amet, consectetur adipisicing elit. A accusamus commodi corporis dicta
		excepturi, harum id, magnam maxime minima molestias nam nostrum perspiciatis possimus quaerat quis rerum
		suscipit ut, voluptate. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias aliquam aperiam
		consectetur culpa dolor dolorem esse in, libero magnam maiores, maxime perspiciatis quasi quod quos ratione sed
		tempore tenetur totam.</p>
{{/wrapWith}}
{{! wrapWith END: Slider}}

toggler.hbs

<div class="c-toggler{{#if
		options.settings.togglerContextClass}}--{{options.settings.togglerContextClass}}{{else}}--default{{/if}}{{#if
		options.settings.togglerClasses}} {{options.settings.togglerClasses}}{{/if}}"{{#if options.settings.togglerId}}
     id="{{options.settings.togglerId}}"{{/if}}
     data-css="c-toggler"{{#if options.settings.togglerJsModule}}{{#unless options.settings.togglerJsModuleWithContext}}
     data-js-module="toggler"{{else}}
     data-js-module="{{options.settings.togglerJsModuleWithContext}}"{{/unless}}{{/if}} {{#if
		options.settings.togglerJsOptions}}
     data-js-options='{{stringify options.settings.togglerJsOptions}}'{{/if}}{{#if options.settings.togglerJsItem}}
     data-js-item="{{options.settings.togglerJsItem}}"{{/if}}{{#each options.settings.attributes}}
	{{name}}="{{value}}"{{/each}}>
	<div class="toggler__wrapper">
		{{{yield}}}
	</div>
</div>

Data File

toggler-bp.hjson

{
	"variations": {
		"default": {
			"docs": {
				"variationName": "Default"
			},
			"settings": {
				"togglerContextClass": "default",
				"togglerClasses": false,
				"togglerJsModule": true,
				"togglerJsOptions": {
					"globalEvent": "toggler:toggle"
				}
			},
			"content": {}
		}
	}
}

Styles

_toggler.scss

/* ===================================================
Component: Toggler
=================================================== */

/* ---------------------------------------------------
Global Variables
--------------------------------------------------- */
$toggler-animation-duration-std: 500ms !default;
$toggler-animation-easing-std: ease-in-out !default;

/* ---------------------------------------------------
Global Styles
--------------------------------------------------- */
[data-css="c-toggler"] {
	height: 0;
	opacity: 0;
	visibility: hidden;
	overflow: hidden;
	transition: opacity $toggler-animation-duration-std $toggler-animation-easing-std, height $toggler-animation-duration-std $toggler-animation-easing-std, visibility 0ms linear $toggler-animation-duration-std;

	&.is-open {
		opacity: 1;
		visibility: visible;
		z-index: 1;
		transition: opacity $toggler-animation-duration-std $toggler-animation-easing-std, height $toggler-animation-duration-std $toggler-animation-easing-std, visibility 0ms linear;
	}

	// !IMPORTANT for calculation
	&.is-calculating {
		position: absolute !important;
		visibility: hidden !important;
		display: block !important;
		height: auto !important;
	}
}

/* ---------------------------------------------------
Context: Default
--------------------------------------------------- */
.c-toggler--default {
}

Scripts

toggler.js

/**
 * Represents a simple toggler with global event binding.
 *
 * @module Toggler
 * @version v1.0.0
 *
 * @author Andy Gutsche
 */

// Global dependencies
import $ from 'jquery';
import Component from '@veams/component';
import transitionEndEvent from '@veams/helpers/lib/detection/transition-end-event';

class Toggler extends Component {
	/**
	 * Generic Props
	 */
	$el = $(this.el);
	savedStyles = this.$el.attr('style');
	windowWidth = this.context.detections.width;
	$toggleTabindexElems = this.options.toggleTabindexElems
		? $(this.options.toggleTabindexElems, this.el)
		: null;

	/**
	 * Constructor for our class
	 *
	 * @see module.js
	 *
	 * @param {Object} obj - Object which is passed to our class
	 * @param {Object} obj.el - element which will be saved in this.el
	 * @param {Object} obj.options - options which will be passed in as JSON object
	 */
	constructor(obj) {
		let options = {
			classes: {
				a11yFocusKey: 'a11y-focus-key',
				calculating: 'is-calculating',
				close: 'is-closed',
				open: 'is-open'
			},
			context: false,
			dataMaxAttr: 'data-js-height',
			focusEl: null,
			globalEvent: '',
			globalEventId: '',
			setOverflow: false,
			toggleTabindexElems: ''
		};

		super(obj, options);
	}

	/**
	 * Get module information
	 */
	static get info() {
		return {
			version: '1.0.0',
			vc: true,
			mod: false
		};
	}

	get height() {
		return this._height;
	}

	set height(height) {
		this._height = height;
	}

	get isOpen() {
		return this._isOpen;
	}

	set isOpen(bool) {
		this._isOpen = bool;
	}

	/**
	 * Get global events
	 *
	 */
	get subscribe() {
		return {
			'{{context.EVENTS.resize}}': 'updateHeight'
		};
	}

	/**
	 * Initialize the view and merge options
	 *
	 */
	didMount() {
		let selfInit =
			this.$el.attr('data-js-module') &&
			this.$el.attr('data-js-module').indexOf('toggler') > -1;

		if (selfInit && !this.options.globalEvent) {
			console.info('@veams/component-toggler :: this.options.globalEvent not set.');
		}

		this.isOpen = this.$el.hasClass(this.options.classes.open);

		this.calculateHeight().then(() => !this.isOpen && this.setHeight(0));
	}

	/**
	 * Bind events
	 *
	 * Listen to open and close events
	 */
	bindEvents() {
		// Listen for addition/removal of child nodes amd update toggler height
		const observer = new MutationObserver(mutations => {
			mutations.forEach(mutation => {
				if (mutation.type === 'childList') {
					this.updateHeight();
				}
			});
		});

		observer.observe(this.el, { childList: true });

		// Global events
		if (this.options.globalEvent) {
			this.registerEvent('{{this.options.globalEvent}}', 'toggle', true);
		}
	}

	/**
	 * Update toggler height
	 *
	 */
	updateHeight() {
		if (this.windowWidth === this.context.detections.width) {
			return;
		}

		this.windowWidth = this.context.detections.width;

		clearTimeout(this.updateHeightTimeout);

		// give browser some time to recalculate
		this.updateHeightTimeout = setTimeout(() => {
			this.calculateHeight().then(() => this.isOpen && this.setHeight());
		}, 200);
	}

	/**
	 * Enable calc mode.
	 *
	 * @private
	 */
	enableCalcMode() {
		if (!this.isOpen) {
			this.$el.addClass(this.options.classes.open);
			this.$el.removeClass(this.options.classes.close);
		}

		this.$el.addClass(this.options.classes.calculating);
	}

	/**
	 * Disable calc mode.
	 *
	 * @private
	 */
	disableCalcMode() {
		this.$el.removeClass(this.options.classes.calculating);

		if (!this.isOpen) {
			this.$el.addClass(this.options.classes.close);
			this.$el.removeClass(this.options.classes.open);
		} else {
			this.setHeight();
		}
	}

	/**
	 * Set height of current view element to given value or latest calculated value.
	 *
	 * @private
	 * @param {Number} [height] - height
	 */
	setHeight(height) {
		this.$el.css(
			'height',
			typeof height === 'number'
				? height + 'px'
				: this.$el.attr(this.options.dataMaxAttr) + 'px'
		);
	}

	/**
	 * Calc the height of current view element.
	 *
	 * @private
	 */
	calcHeight() {
		return new Promise((resolve, reject) => {
			clearTimeout(this.calcHeightTimeout);

			this.calcHeightTimeout = setTimeout(() => {
				let wantedHeight = this.$el.outerHeight();

				this.$el.attr(this.options.dataMaxAttr, wantedHeight);
				this.height = wantedHeight !== this.height ? wantedHeight : this.height;

				resolve();
			}, 10);
		});
	}

	/**
	 * calculateHeight class
	 */
	calculateHeight() {
		return new Promise((resolve, reject) => {
			if (this.el && this.el.hasAttribute('style')) {
				this.saveStyles();
			}

			this.enableCalcMode(true);

			this.calcHeight().then(() => {
				if (this.savedStyles) {
					this.restoreStyles();
				}

				this.disableCalcMode();

				resolve();
			});
		});
	}

	/**
	 * Save all styles from current view element
	 *
	 * @private
	 */
	saveStyles() {
		this.savedStyles = this.$el.attr('style');
		this.$el.removeAttr('style');
	}

	/**
	 * Restore all styles from current view element
	 *
	 * @private
	 */
	restoreStyles() {
		this.$el.attr('style', this.savedStyles);
		this.savedStyles = null;
	}

	/**
	 * Toggles content
	 *
	 * @public
	 *
	 * @param {Object} obj - the event data
	 * @param {Boolean} obj.isActive - indicates if panel should open or close itself
	 * @param {String} obj.options.setFocus - element to set focus on open
	 */
	toggle(obj) {
		// if globalEventId is set on both (cta and toggler)
		if (this.options.globalEventId && obj.options && obj.options.globalEventId) {
			// stop here if global event id don't match
			if (this.options.globalEventId !== obj.options.globalEventId) {
				return;
			}
		}

		if (obj.isActive) {
			this.open(obj);
		} else {
			this.close();
		}
	}

	/**
	 * Open current view element
	 *
	 * @public
	 *
	 * @param {Object} [obj] - the event object
	 * @param {Boolean} [obj.isActive] - indicates if panel should open or close itself
	 * @param {String} [obj.options.setFocus] - element to set focus on open
	 */
	open(obj) {
		this.$el
			.css('height', this.$el.attr(this.options.dataMaxAttr) + 'px')
			.attr('aria-hidden', false)
			.removeClass(this.options.classes.close)
			.addClass(this.options.classes.open);

		this.$srcEl = obj && $(obj.el);

		if (this.$toggleTabindexElems && this.$toggleTabindexElems.length) {
			this.$el.on(transitionEndEvent(), () => {
				this.$toggleTabindexElems.attr('tabindex', 0);

				if (this.$srcEl.hasClass(this.options.classes.a11yFocusKey)) {
					this.$toggleTabindexElems.eq(0).addClass(this.options.classes.a11yFocusKey);
				}

				this.$toggleTabindexElems[0].focus();
				this.$el.off(transitionEndEvent());
			});
		}

		this.context.Vent.trigger(this.context.EVENTS.toggler.open, {
			context: this.options.context
		});

		if (this.options.setOverflow) {
			this.$el.on(transitionEndEvent(), () => {
				this.$el.css('overflow', 'visible');
				this.$el.off(transitionEndEvent());
			});
		}

		this.isOpen = true;
	}

	/**
	 * Close current view element
	 *
	 * @public
	 */
	close() {
		this.$el
			.removeAttr('style')
			.css('height', 0)
			.attr('aria-hidden', true)
			.removeClass(this.options.classes.open)
			.addClass(this.options.classes.close);

		if (this.options.setOverflow) {
			this.$el.css('overflow', 'hidden');
		}

		if (this.$toggleTabindexElems && this.$toggleTabindexElems.length) {
			this.$toggleTabindexElems.attr('tabindex', -1);
		}

		this.isOpen = false;
	}
}

export default Toggler;

HTML Output

Default

<ul>
	<li>
		<a href="#" onclick="Veams.Vent.publish(Veams.EVENTS.toggler.toggle, {isActive: true})">Open the content</a>
	</li>
	<li>
		<a href="#" onclick="Veams.Vent.publish(Veams.EVENTS.toggler.toggle, {isActive: false})">Close the content</a>
	</li>
</ul>
<div class="c-toggler--default" data-css="c-toggler" data-js-module="toggler" data-js-options='{&quot;globalEvent&quot;:&quot;toggler:toggle&quot;}'>
	<div class="toggler__wrapper">
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A culpa deleniti distinctio eligendi enim explicabo,
			incidunt laborum laudantium magnam minus mollitia, perspiciatis porro quibusdam quis ratione reiciendis sapiente
			temporibus vel. Lorem ipsum dolor sit amet, consectetur adipisicing elit. A accusamus commodi corporis dicta
			excepturi, harum id, magnam maxime minima molestias nam nostrum perspiciatis possimus quaerat quis rerum
			suscipit ut, voluptate. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias aliquam aperiam
			consectetur culpa dolor dolorem esse in, libero magnam maiores, maxime perspiciatis quasi quod quos ratione sed
			tempore tenetur totam.</p>
	</div>
</div>

Wonach suchst du?