From 3e9a83660d0f251ea2129f7c500c0b81165aaabb Mon Sep 17 00:00:00 2001 From: alien1976 Date: Wed, 5 Mar 2025 11:31:59 +0200 Subject: [PATCH] Reworked some of the components with shadow dom The source is not polished and has beed done in this way just for the research --- components/automatic-grid/index.html | 144 +++- components/automatic-grid/script.js | 79 +- components/carousel/index.html | 133 +++- components/carousel/script.js | 177 +++-- components/carousel/style.css | 2 +- components/checkbox/index.html | 85 ++- components/checkbox/script.js | 96 ++- components/color-picker/colorPickerUtils.js | 2 +- components/color-picker/index.html | 111 ++- components/color-picker/script.js | 234 +++++- components/form-control/index.html | 163 +++-- components/form-control/script.js | 9 +- components/modal/index.html | 85 ++- components/modal/script.js | 135 +++- components/progress-bar/index.html | 98 ++- components/progress-bar/script.js | 49 +- components/radial-menu/index.html | 136 +++- components/radial-menu/script.js | 160 +++- components/radio-button/index.html | 40 +- components/radio-button/script.js | 110 ++- components/radio-button/style.css | 4 +- components/rangeslider/index.html | 5 +- .../rangesliders/rangeSliderBase.js | 42 +- .../singleHandleSliders/basicRangeslider.js | 7 +- .../singleHandleRangeSliderBase.js | 211 +++++- .../singleHandleSliders/valuesRangeslider.js | 6 +- .../basicTwoHandlesRangeSlider.js | 6 +- .../twoHandlesRangeSliderBase.js | 213 +++++- components/rangeslider/script.js | 12 +- .../scrollable-container/index copy.html | 147 ++++ components/scrollable-container/index.html | 28 +- components/scrollable-container/script.js | 167 +++-- components/scrollable-container/slider.js | 527 +++++++++++++ components/scrollable-container/template.html | 7 - components/slider/index.html | 100 ++- components/slider/script.js | 239 +++++- components/slider/styles/vertical.css | 3 +- components/slider/templates/horizontal.html | 68 +- components/slider/templates/vertical.html | 67 +- components/stepper/index.html | 6 +- components/stepper/script.js | 148 +++- components/stepper/template.html | 63 +- components/switch/index.html | 51 +- components/switch/script.js | 692 +++++++++++------- components/tabs/index.html | 35 +- components/tabs/script.js | 528 +++++++------ components/text-field/index.html | 10 +- components/text-field/script.js | 231 +++++- components/toast/index.html | 4 +- components/toast/script.js | 187 ++++- components/tooltip/index.html | 82 ++- components/tooltip/script.js | 64 +- lib/components.js | 19 +- 53 files changed, 4807 insertions(+), 1220 deletions(-) create mode 100644 components/scrollable-container/index copy.html create mode 100644 components/scrollable-container/slider.js delete mode 100644 components/scrollable-container/template.html diff --git a/components/automatic-grid/index.html b/components/automatic-grid/index.html index 929a8b5eb..b197a959e 100644 --- a/components/automatic-grid/index.html +++ b/components/automatic-grid/index.html @@ -1,10 +1,15 @@ - - - - + + + + - - - - 1 - 2 - 3 - 4 - 5 - 6 + + 1 + 2 + 3 + 4 + 5 + 6 + + + - + \ No newline at end of file diff --git a/components/automatic-grid/script.js b/components/automatic-grid/script.js index a8a6ebbed..d434e59bb 100644 --- a/components/automatic-grid/script.js +++ b/components/automatic-grid/script.js @@ -4,9 +4,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import template from './template.html'; +// import { Components } from 'coherent-gameface-components'; +// const components = new Components(); +// import template from './template.html'; +import { components } from '../../lib/components.js'; + +const templateCSS = ` + + +`; + +const templateHTML = ` +
+
+ +
+`; const maxColumns = 12; // Max number of columns as it's based on the grid component const BaseComponent = components.BaseComponent; @@ -34,34 +47,18 @@ class AutomaticGrid extends BaseComponent { /** * @constructor + * @param {string} additionalStyles */ - constructor() { + constructor(additionalStyles) { super(); // use the template to create the base grid - this.template = template; + // this.template = template; + // const additionalStyles = document.querySelector('[data-automatic-grid]'); + this.template = templateCSS + `` + templateHTML; this.dragStart = this.dragStart.bind(this); this.dragMove = this.dragMove.bind(this); this.dragEnd = this.dragEnd.bind(this); - this.init = this.init.bind(this); - } - - /** - * Initialize the custom component. - * Set template, attach event listeners, setup initial state etc. - * @param {object} data - */ - init(data) { - this.setupTemplate(data, () => { - // render the template - components.renderOnce(this); - - // Get the grid container, where all of the cells will be - this._gridContainer = this.querySelector('.guic-automatic-grid-container'); - - this.buildGrid(); - this.addItemsToCells(); - }); } /** @@ -82,10 +79,13 @@ class AutomaticGrid extends BaseComponent { // The array of cells this._cells = []; - // Load the template - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + + this._gridContainer = this.shadowRoot.querySelector('.guic-automatic-grid-container'); + + this.buildGrid(); + this.addItemsToCells(); } /** @@ -104,6 +104,7 @@ class AutomaticGrid extends BaseComponent { const element = document.createElement('div'); element.classList.add('guic-automatic-grid-cell'); + element.setAttribute('part', 'cell'); element.classList.add(`guic-col-${AutomaticGrid.formatFloat(maxColumns / this._columns)}`); // We add the grid class to each cell based on the number of columns element.dataset.col = (i % this._columns) + 1; // We set the cell column so that it's available if we need it later. +1 so that columns don't start from 0 @@ -122,7 +123,15 @@ class AutomaticGrid extends BaseComponent { */ addItemsToCells() { // The items we have added to the grid - const items = Array.from(this.querySelectorAll('component-slot')); + const items = Array.from(this.querySelectorAll('[slot="item"]')); + // items.forEach((item) => { + // item.addEventListener('mouseup', (event) => { + // this.dispatchEvent(new MouseEvent('mouseup', { + // bubbles: true, + // composed: true, + // })); + // }); + // }); // We check if an item has data-bind-for and we skip adding the items before the data-binding. After data-binding the attribute is "data-bind-meta-for" if (items.findIndex(item => item.hasAttribute('data-bind-for')) >= 0) return; @@ -189,6 +198,7 @@ class AutomaticGrid extends BaseComponent { dragStart(event) { // We set the draggedItem to the one we are dragging so it can be used in other functions. this._draggedItem = event.currentTarget; + // const target = this.shadowRoot.elementFromPoint(event.clientX, event.clientY); // Calculate offsetX and offsetY from the top left corner of the dragged item const offsetX = event.clientX - this._draggedItem.getBoundingClientRect().x; @@ -223,19 +233,20 @@ class AutomaticGrid extends BaseComponent { * @param {HTMLEvent} event */ dragEnd(event) { + const target = this.shadowRoot.elementFromPoint(event.clientX, event.clientY); + // Removes the class that was added when the drag started this._draggedItem.classList.remove('guic-dragged'); - this.dropItem(event.target); + this.dropItem(target); // Reset the registry point to the top left this._draggedItem.style.transform = `translateX(0) translateY(0)`; - // Removes the dragged item - this._draggedItem = null; - document.removeEventListener('mousemove', this.dragMove); document.removeEventListener('mouseup', this.dragEnd); + // Removes the dragged item + this._draggedItem = null; } /** @@ -281,4 +292,4 @@ class AutomaticGrid extends BaseComponent { } components.defineCustomElement('gameface-automatic-grid', AutomaticGrid); -export default AutomaticGrid; +// customElements.define('gameface-automatic-grid', AutomaticGrid); diff --git a/components/carousel/index.html b/components/carousel/index.html index fa3f07c8d..e2047cb7b 100644 --- a/components/carousel/index.html +++ b/components/carousel/index.html @@ -2,7 +2,10 @@ - + + + + `; + // this.init = this.init.bind(this); this._pageSize = 2; this._navArrowStepSize = 1; @@ -37,29 +101,48 @@ class Carousel extends BaseComponent { /* eslint-disable-next-line require-jsdoc */ connectedCallback() { - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + + this.contentWrapper = this.shadowRoot.querySelector(CONTENT_WRAPPER_SELECTOR); + // window.requestAnimationFrame(() => { + // window.requestAnimationFrame(() => { + // window.requestAnimationFrame(() => { + this.initSize(); + + this.style.visibility = 'visible'; + + this.createPaginationControls(); + this.attachControlButtonsListeners(); + + this.shouldShowNavArrow(DIRECTIONS.RIGHT, this.nextStepIndex(this.navArrowStepSize)); + this.shouldShowNavArrow(DIRECTIONS.LEFT, this.prevStepIndex(this.navArrowStepSize)); + // }); + // }); + // }); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /* eslint-disable-next-line require-jsdoc */ - init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); + // init(data) { + // this.setupTemplate(data, () => { + // components.renderOnce(this); - this.contentWrapper = this.querySelector(CONTENT_WRAPPER_SELECTOR); - components.waitForFrames(() => this.initSize()); - this.style.visibility = 'visible'; + // this.contentWrapper = this.shadowRoot.querySelector(CONTENT_WRAPPER_SELECTOR); + // components.waitForFrames(() => this.initSize()); + // this.style.visibility = 'visible'; - this.createPaginationControls(); - this.attachControlButtonsListeners(); + // this.createPaginationControls(); + // this.attachControlButtonsListeners(); - this.shouldShowNavArrow(DIRECTIONS.RIGHT, this.nextStepIndex(this.navArrowStepSize)); - this.shouldShowNavArrow(DIRECTIONS.LEFT, this.prevStepIndex(this.navArrowStepSize)); + // this.shouldShowNavArrow(DIRECTIONS.RIGHT, this.nextStepIndex(this.navArrowStepSize)); + // this.shouldShowNavArrow(DIRECTIONS.LEFT, this.prevStepIndex(this.navArrowStepSize)); - this.isRendered = true; - }); - } + // this.isRendered = true; + // }); + // } /** * Setup the sized of the carouse based on the items @@ -68,6 +151,7 @@ class Carousel extends BaseComponent { initSize() { if (!this.items || !this.items[0]) return console.warn('No items were added to the carousel!'); const { width, height } = this.items[0].getBoundingClientRect(); + console.log(width, height); this.itemWidth = width; this.itemHeight = height; @@ -87,7 +171,7 @@ class Carousel extends BaseComponent { * Return all carousel items. */ get items() { - return this.querySelector(CONTENT_WRAPPER_SELECTOR).children; + return this.shadowRoot.querySelector(CONTENT_WRAPPER_SELECTOR).assignedElements(); } /** @@ -109,9 +193,13 @@ class Carousel extends BaseComponent { } }); - components.waitForFrames(() => { - this.initSize(); - this.createPaginationControls(); + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + this.initSize(); + this.createPaginationControls(); + }); + }); }); } @@ -143,14 +231,14 @@ class Carousel extends BaseComponent { * Return the left navigation arrow HTML Element. */ get leftArrow() { - return document.querySelector(PREV_ARROW_SELECTOR); + return this.shadowRoot.querySelector(PREV_ARROW_SELECTOR); } /** * Return the right navigation arrow HTML Element. */ get rightArrow() { - return document.querySelector(NEXT_ARROW_SELECTOR); + return this.shadowRoot.querySelector(NEXT_ARROW_SELECTOR); } /** @@ -307,14 +395,15 @@ class Carousel extends BaseComponent { * @param {index} index - the position at which to add it. */ addItem(node, index) { - if (index === undefined || index < 0) { - this.contentWrapper.appendChild(node); - } else { - const referenceNode = this.items[index - 1]; - referenceNode.parentNode.insertBefore(node, referenceNode); - } + this.appendChild(node); + // if (index === undefined || index < 0) { + // } else { + // const referenceNode = this.items[index - 1]; + // referenceNode.parentNode.insertBefore(node, referenceNode); + // } - this.createPaginationControls(); + this.rerenderControls(); + // this.createPaginationControls(); } /** @@ -323,9 +412,9 @@ class Carousel extends BaseComponent { */ removeItem(index = 0) { const items = this.items; - const itemsArr = Array.from(items); - itemsArr[index].remove(); - this.createPaginationControls(); + // const itemsArr = Array.from(items); + items[index].remove(); + this.rerenderControls(); } /** @@ -391,7 +480,7 @@ class Carousel extends BaseComponent { * Create the pagination controls - the dots and attach click event handlers */ createPaginationControls() { - const container = this.querySelector(DOTS_CONTAINER_SELECTOR); + const container = this.shadowRoot.querySelector(DOTS_CONTAINER_SELECTOR); container.innerHTML = ''; for (let i = 0; i < this.pagesCount; i++) { @@ -426,8 +515,8 @@ class Carousel extends BaseComponent { * Resize the carousel based on the size of the elements. */ resize() { - this.querySelector(CAROUSEL_SELECTOR).style.width = this.pageSize * this.itemWidth + 'px'; - this.querySelector(CAROUSEL_SELECTOR).style.height = this.itemHeight + 'px'; + this.shadowRoot.querySelector(CAROUSEL_SELECTOR).style.width = this.pageSize * this.itemWidth + 'px'; + this.shadowRoot.querySelector(CAROUSEL_SELECTOR).style.height = this.itemHeight + 'px'; this.style.width = this.pageSize * this.itemWidth + 'px'; } @@ -435,8 +524,8 @@ class Carousel extends BaseComponent { * Attach the event handlers of the control buttons - next, previous */ attachControlButtonsListeners() { - const singleNextButton = this.querySelector(NEXT_BTN_SELECTOR); - const singlePreviousButton = this.querySelector(PREV_BTN_SELECTOR); + const singleNextButton = this.shadowRoot.querySelector(NEXT_BTN_SELECTOR); + const singlePreviousButton = this.shadowRoot.querySelector(PREV_BTN_SELECTOR); singleNextButton.addEventListener('click', _ => this.next(1)); singlePreviousButton.addEventListener('click', _ => this.previous(1)); @@ -452,5 +541,5 @@ class Carousel extends BaseComponent { this.shouldShowNavArrow(DIRECTIONS.LEFT, this.prevStepIndex(this.navArrowStepSize)); } } + components.defineCustomElement('gameface-carousel', Carousel); -export default Carousel; diff --git a/components/carousel/style.css b/components/carousel/style.css index 77195cbc5..7c1a87a65 100644 --- a/components/carousel/style.css +++ b/components/carousel/style.css @@ -15,7 +15,7 @@ gameface-carousel { overflow: hidden; } -.guic-carousel-content-wrapper { +.guic-carousel-content-wrapper, [name="carousel-content"] { display: flex; position: absolute; left: 0px; diff --git a/components/checkbox/index.html b/components/checkbox/index.html index 29259bd9f..3e74d4c5b 100644 --- a/components/checkbox/index.html +++ b/components/checkbox/index.html @@ -4,37 +4,74 @@ - - - + + + Document - -
-
- - Enable Music - + +
+ + + Enable Music +
- - -
-
- - Enable Music 1 - + + +
+ + + Enable Music 1 +
- - -
-
- - Enable Music 2 - + + +
+ + + Enable Music 2 +
+ - + \ No newline at end of file diff --git a/components/checkbox/script.js b/components/checkbox/script.js index d5d6603de..5b9bae731 100644 --- a/components/checkbox/script.js +++ b/components/checkbox/script.js @@ -2,11 +2,72 @@ * Copyright (c) Coherent Labs AD. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -import template from './template.html'; +import { components } from '../../lib/components.js'; +const { CustomElementValidator } = components; -const components = new Components(); -const CustomElementValidator = components.CustomElementValidator; +const template = ` + +
+
+ +
+
+ +
+ Click me! +
+`; + +// const components = new Components(); +// const CustomElementValidator = components.CustomElementValidator; /** * Class definition of the gameface checkbox custom element @@ -78,7 +139,7 @@ class Checkbox extends CustomElementValidator { */ updateCheckedState(value) { this.updateState('checked', value); - this.querySelector('[data-name="check-mark"]').style.display = value ? 'block' : 'none'; + this.shadowRoot.querySelector('slot[name="check-mark"]').style.display = value ? 'block' : 'none'; } // eslint-disable-next-line require-jsdoc @@ -134,10 +195,10 @@ class Checkbox extends CustomElementValidator { this.updateState('disabled', value); if (value) { - this.firstChild.classList.add('guic-checkbox-disabled'); + this.componentWrapper.classList.add('guic-checkbox-disabled'); this.setAttribute('tabindex', '-1'); } else { - this.firstChild.classList.remove('guic-checkbox-disabled'); + this.componentWrapper.classList.remove('guic-checkbox-disabled'); this.setAttribute('tabindex', '0'); } } @@ -186,18 +247,23 @@ class Checkbox extends CustomElementValidator { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - this.addEventListener('click', this.toggleChecked); - this.initCheckboxState(); - }); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.componentWrapper = this.shadowRoot.querySelector('.guic-checkbox-wrapper'); + this.addEventListener('click', this.toggleChecked); + this.initCheckboxState(); + // }); } // eslint-disable-next-line require-jsdoc connectedCallback() { - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /** diff --git a/components/color-picker/colorPickerUtils.js b/components/color-picker/colorPickerUtils.js index d74472f60..ed3ef7ecb 100644 --- a/components/color-picker/colorPickerUtils.js +++ b/components/color-picker/colorPickerUtils.js @@ -1,4 +1,4 @@ -import hexTransperancies from './hexTransperancies'; +import hexTransperancies from './hexTransperancies.js'; /** * Clamp a value between a minimum and maximum value. diff --git a/components/color-picker/index.html b/components/color-picker/index.html index 83a3757d8..535a9db7e 100644 --- a/components/color-picker/index.html +++ b/components/color-picker/index.html @@ -1,48 +1,83 @@ - - - - - - - + gameface-tooltip { + background-color: transparent; + width: auto; + } + + - - -

Using the color picker with the coherent-gameface-tooltip

-
-
+ + +

Using the color picker with the coherent-gameface-tooltip

+
+
+
+ +
+
- -
- -
-
- +
+ + + + \ No newline at end of file diff --git a/components/color-picker/script.js b/components/color-picker/script.js index 824c05d4e..117d55a62 100644 --- a/components/color-picker/script.js +++ b/components/color-picker/script.js @@ -1,10 +1,188 @@ -import { Components } from 'coherent-gameface-components'; -import 'coherent-gameface-rangeslider'; -import template from './template.html'; -import { clamp, hslaToHexAndRGB } from './colorPickerUtils'; -import { ColorTranslator } from 'colortranslator'; +import { components } from '../../lib/components.js'; +import '../rangeslider/script.js'; +// import template from './template.html'; +import { clamp, hslaToHexAndRGB } from './colorPickerUtils.js'; +import { ColorTranslator } from './node_modules/colortranslator/esm/index.js'; + +const template = ` + +
+
+
+
+
+ +
+
+ +
+
+
+
HEX
+
RGBA
+
+
+
+
+
+ +
+
+
+`; +// const components = new Components(); const BaseComponent = components.BaseComponent; /** @@ -53,37 +231,39 @@ class ColorPicker extends BaseComponent { } init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - - this.mode = 'HEX'; + // this.setupTemplate(data, () => { + // components.renderOnce(this); - this.lsPicker = this.querySelector('.guic-ls-picker'); + this.mode = 'HEX'; + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.lsPicker = this.shadowRoot.querySelector('.guic-ls-picker'); - this.lsPickerHandle = this.querySelector('.guic-ls-picker-handle'); - this.lsPickerAttributeStyleMap = this.lsPickerHandle.attributeStyleMap; + this.lsPickerHandle = this.shadowRoot.querySelector('.guic-ls-picker-handle'); + this.lsPickerAttributeStyleMap = this.lsPickerHandle.attributeStyleMap; - this.colorBox = this.querySelector('.guic-color-preview-box-color'); + this.colorBox = this.shadowRoot.querySelector('.guic-color-preview-box-color'); - this.huePicker = this.querySelector('.guic-hue-picker-slider'); - this.alphaPicker = this.querySelector('.guic-alpha-picker-slider'); + this.huePicker = this.shadowRoot.querySelector('.guic-hue-picker-slider'); + this.alphaPicker = this.shadowRoot.querySelector('.guic-alpha-picker-slider'); - this.colorInput = this.querySelector('.guic-color-preview-input'); - this.tabs = this.querySelectorAll('.guic-color-preview-tab'); + this.colorInput = this.shadowRoot.querySelector('.guic-color-preview-input'); + this.tabs = this.shadowRoot.querySelectorAll('.guic-color-preview-tab'); - this.value = this.getAttribute('value'); + this.value = this.getAttribute('value'); - - this.attachEventListeners(); - this.isRendered = true; - }); + this.attachEventListeners(); + this.isRendered = true; + // }); } connectedCallback() { - components - .loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components + // .loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } disconnectedCallback() { diff --git a/components/form-control/index.html b/components/form-control/index.html index ef64c5e12..c420380f5 100644 --- a/components/form-control/index.html +++ b/components/form-control/index.html @@ -4,15 +4,16 @@ - + + +
+
+
+
x
+
+ Put your title here. +
+
+ Put the content here. +
+ +
+
+`; const BaseComponent = components.BaseComponent; /** @@ -22,7 +129,7 @@ class Modal extends BaseComponent { this.state = { display: 'none' }; this.closeBound = e => this.close(e); - this.url = '/components/modal/template.html'; + // this.url = '/components/modal/template.html'; this.init = this.init.bind(this); } @@ -32,24 +139,28 @@ class Modal extends BaseComponent { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - this.attachEventListeners(); - }); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.attachEventListeners(); + // }); } // eslint-disable-next-line require-jsdoc connectedCallback() { - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /** * Method that will attach click event listeners to all close buttons */ attachEventListeners() { - const closeButtons = this.querySelectorAll('.close'); + const closeButtons = this.shadowRoot.querySelectorAll('.close'); for (let i = 0; i < closeButtons.length; i++) { closeButtons[i].addEventListener('click', this.closeBound); } diff --git a/components/progress-bar/index.html b/components/progress-bar/index.html index 7d111c2b4..a41baa9b1 100644 --- a/components/progress-bar/index.html +++ b/components/progress-bar/index.html @@ -3,8 +3,11 @@ - - + + +
+
+
+`; const BaseComponent = components.BaseComponent; /** @@ -95,20 +115,23 @@ class ProgressBar extends BaseComponent { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - - // Get the filler element when the component is rendered. - this.filler = this.querySelector('.guic-progress-bar-filler'); - this.setProgress(); - }); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + // Get the filler element when the component is rendered. + this.filler = this.shadowRoot.querySelector('.guic-progress-bar-filler'); + this.setProgress(); + // }); } // eslint-disable-next-line require-jsdoc connectedCallback() { - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /** diff --git a/components/radial-menu/index.html b/components/radial-menu/index.html index ee1bb4003..568a12fc1 100644 --- a/components/radial-menu/index.html +++ b/components/radial-menu/index.html @@ -1,9 +1,13 @@ + - - + + + - - -

Press Shift key to open a radial menu with custom center part

-

Press Space key to open the default radial menu

- -
-
-
-
-
- - - + + +

Press Shift key to open a radial menu with custom center part

+

Press Space key to open the default radial menu

+ +
+
+
+
+
+ + + + + - + \ No newline at end of file diff --git a/components/radial-menu/script.js b/components/radial-menu/script.js index 7d4d8030f..5b9d8497b 100644 --- a/components/radial-menu/script.js +++ b/components/radial-menu/script.js @@ -4,9 +4,137 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import template from './template.html'; +import { components } from '../../lib/components.js'; +// const components = new Components(); +// import template from './template.html'; + +const template = ` + +
+
+ +
+
Radial Menu
+
+
+
+
+
+
+
+
+
+
+
`; const BaseComponent = components.BaseComponent; @@ -57,16 +185,20 @@ class RadialMenu extends BaseComponent { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - }); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + // this.setupTemplate(data, () => { + // components.renderOnce(this); + // }); } // eslint-disable-next-line require-jsdoc connectedCallback() { - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } // eslint-disable-next-line require-jsdoc @@ -108,10 +240,10 @@ class RadialMenu extends BaseComponent { * Add the menu items */ populateItems() { - const itemsElement = this.getElementsByClassName('guic-radial-menu-items')[0]; + const itemsElement = this.shadowRoot.querySelector('.guic-radial-menu-items'); this.segmentDegrees = 360 / this.itemsCount; - const itemsSelectorElement = this.querySelector('.guic-radial-menu-selector'); + const itemsSelectorElement = this.shadowRoot.querySelector('.guic-radial-menu-selector'); itemsElement.textContent = ''; itemsElement.appendChild(itemsSelectorElement); @@ -311,10 +443,10 @@ class RadialMenu extends BaseComponent { this.selectAndClose = this.selectAndClose.bind(this); this.updateRadialMenuCenterXY = this.updateRadialMenuCenterXY.bind(this); - this.radialMenuTemplateWrapper = this.querySelector('.guic-radial-menu'); - this.itemSelector = this.querySelector('.guic-radial-menu-selector'); + this.radialMenuTemplateWrapper = this.shadowRoot.querySelector('.guic-radial-menu'); + this.itemSelector = this.shadowRoot.querySelector('.guic-radial-menu-selector'); - const centerText = this.querySelector('.guic-radial-menu-center-text'); + const centerText = this.shadowRoot.querySelector('.guic-radial-menu-center-text'); if (centerText) centerText.textContent = this.dataset.name; this.populateItems(); diff --git a/components/radio-button/index.html b/components/radio-button/index.html index 5ae7d2d3f..46aceddc7 100644 --- a/components/radio-button/index.html +++ b/components/radio-button/index.html @@ -3,8 +3,14 @@ - - + + +
+ +
+
+
+
+ +`; const KEYCODES = components.KEYCODES; const BaseComponent = components.BaseComponent; @@ -17,7 +96,6 @@ class GamefaceRadioGroup extends HTMLElement { // eslint-disable-next-line require-jsdoc constructor() { super(); - this.previouslyCheckedElement = null; } @@ -325,10 +403,10 @@ class RadioButton extends BaseComponent { this.updateState('disabled', value); if (value) { - this.firstChild.classList.add('guic-radio-button-disabled'); + this.buttonContainer.classList.add('guic-radio-button-disabled'); this.setAttribute('tabindex', '-1'); } else { - this.firstChild.classList.remove('guic-radio-button-disabled'); + this.buttonContainer.classList.remove('guic-radio-button-disabled'); this.setAttribute('tabindex', '0'); } } @@ -399,25 +477,31 @@ class RadioButton extends BaseComponent { // use text content if there is no slot if (!hasSlots) radioButtonText = this.textContent; - this.setupTemplate(data, () => { - components.renderOnce(this); - this.textElement = this.querySelector('.radio-button-text'); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.buttonContainer = this.shadowRoot.querySelector('.radio-button'); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + components.waitForFrames(() => { + this.textElement = this.shadowRoot.querySelector('.radio-button-text'); if (!hasSlots) this.textElement.textContent = radioButtonText; // Apply the user set text if (this.hasAttribute('checked')) this.updateAttributeState('checked', true); if (this.hasAttribute('disabled')) this.updateAttributeState('disabled', true); if (this.hasAttribute('value')) this.updateAttributeState('value', this.getAttribute('value')); }); + // }); } // eslint-disable-next-line require-jsdoc connectedCallback() { // Get the text set from the user before applying the template. this.radioGroup = this.parentElement; - - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } } diff --git a/components/radio-button/style.css b/components/radio-button/style.css index c1d111ff5..2f4524e8d 100644 --- a/components/radio-button/style.css +++ b/components/radio-button/style.css @@ -21,9 +21,9 @@ cursor: pointer; } -[role="radio"] + [role="radio"] { +/* [role="radio"] + [role="radio"] { margin-left: 16px; -} +} */ [role="radio"] .before, [role="radio"] .after { diff --git a/components/rangeslider/index.html b/components/rangeslider/index.html index d96ad68fc..722efdd9a 100644 --- a/components/rangeslider/index.html +++ b/components/rangeslider/index.html @@ -4,9 +4,9 @@ - + +
+
+
+
+
+
+`; + +const horizontalTemplate = ` + +
+
+
+
+
+
+`; /** * This class holds common methods and data for all the rangesliders with a single handle @@ -76,7 +271,7 @@ export default class SingleHandleRangeSliderBase extends RangeSliderBase { */ setup() { components.waitForFrames(() => { - this.handle = this.rangeslider.querySelector(`.guic-${this.rangeslider.orientation}-rangeslider-handle`); + this.handle = this.rangeslider.shadowRoot.querySelector(`.guic-${this.rangeslider.orientation}-rangeslider-handle`); this.setupSlider(); }, 3); } @@ -89,7 +284,7 @@ export default class SingleHandleRangeSliderBase extends RangeSliderBase { if (this.thumb) { this.buildThumb(this.value); - this.thumbElement = this.rangeslider.querySelector(`.guic-${this.rangeslider.orientation}-rangeslider-thumb`); + this.thumbElement = this.rangeslider.shadowRoot.querySelector(`.guic-${this.rangeslider.orientation}-rangeslider-thumb`); } } diff --git a/components/rangeslider/rangesliders/singleHandleSliders/valuesRangeslider.js b/components/rangeslider/rangesliders/singleHandleSliders/valuesRangeslider.js index ada119eda..25918b57a 100644 --- a/components/rangeslider/rangesliders/singleHandleSliders/valuesRangeslider.js +++ b/components/rangeslider/rangesliders/singleHandleSliders/valuesRangeslider.js @@ -1,7 +1,7 @@ -import SingleHandleRangeSliderBase from './singleHandleRangeSliderBase'; +import SingleHandleRangeSliderBase from './singleHandleRangeSliderBase.js'; // eslint-disable-next-line no-unused-vars -import Rangeslider from '../../script'; -import { clamp } from '../rangeSliderUtils'; +import Rangeslider from '../../script.js'; +import { clamp } from '../rangeSliderUtils.js'; /** * This is the rangeslider with values array which has single thumb and works with string values. diff --git a/components/rangeslider/rangesliders/twoHandlesSliders/basicTwoHandlesRangeSlider.js b/components/rangeslider/rangesliders/twoHandlesSliders/basicTwoHandlesRangeSlider.js index 24c8e3f9e..d2b919306 100644 --- a/components/rangeslider/rangesliders/twoHandlesSliders/basicTwoHandlesRangeSlider.js +++ b/components/rangeslider/rangesliders/twoHandlesSliders/basicTwoHandlesRangeSlider.js @@ -1,7 +1,7 @@ -import TwoHandlesRangeSliderBase from './twoHandlesRangeSliderBase'; +import TwoHandlesRangeSliderBase from './twoHandlesRangeSliderBase.js'; // eslint-disable-next-line no-unused-vars -import Rangeslider from '../../script'; -import { clamp, valueToPercent } from '../rangeSliderUtils'; +import Rangeslider from '../../script.js'; +import { clamp, valueToPercent } from '../rangeSliderUtils.js'; const SPACE_BETWEEN_GRID_POLS = 10; /** diff --git a/components/rangeslider/rangesliders/twoHandlesSliders/twoHandlesRangeSliderBase.js b/components/rangeslider/rangesliders/twoHandlesSliders/twoHandlesRangeSliderBase.js index 56b564476..29666bf48 100644 --- a/components/rangeslider/rangesliders/twoHandlesSliders/twoHandlesRangeSliderBase.js +++ b/components/rangeslider/rangesliders/twoHandlesSliders/twoHandlesRangeSliderBase.js @@ -1,10 +1,207 @@ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import verticalTemplateTwoHandles from '../../templates/verticalTwoHandles.html'; -import horizontalTemplateTwoHandles from '../../templates/horizontalTwoHandles.html'; +import { components } from '../../../../lib/components.js'; +// const components = new Components(); +// import verticalTemplateTwoHandles from '../../templates/verticalTwoHandles.html'; +// import horizontalTemplateTwoHandles from '../../templates/horizontalTwoHandles.html'; // eslint-disable-next-line no-unused-vars -import Rangeslider from '../../script'; -import RangeSliderBase from '../rangesliderBase'; +import Rangeslider from '../../script.js'; +import RangeSliderBase from '../rangesliderBase.js'; + +const commonStyles = ` +.handle-0[active], +.handle-1[active] { + border-style: solid; + border-width: 2px; + border-color: #0085a7; + z-index: 10; +}`; + +const verticalTemplateTwoHandles = ` + +
+
+
+
+
+
+
+`; + +const horizontalTemplateTwoHandles = ` + +
+
+
+
+
+
+
+`; /** * This class holds common methods and data for all the rangesliders @@ -76,7 +273,7 @@ export default class TwoHandlesRangeSliderBase extends RangeSliderBase { if (this.thumb) { // creates two thumbs this.value.forEach(val => this.buildThumb(val)); - this.thumbElement = this.rangeslider.querySelectorAll(`.guic-${this.rangeslider.orientation}-rangeslider-thumb`); + this.thumbElement = this.rangeslider.shadowRoot.querySelectorAll(`.guic-${this.rangeslider.orientation}-rangeslider-thumb`); } } @@ -97,7 +294,7 @@ export default class TwoHandlesRangeSliderBase extends RangeSliderBase { */ setup() { components.waitForFrames(() => { - this.handle = this.rangeslider.querySelectorAll(`.guic-${this.rangeslider.orientation}-rangeslider-handle`); + this.handle = this.rangeslider.shadowRoot.querySelectorAll(`.guic-${this.rangeslider.orientation}-rangeslider-handle`); this.setupSlider(); }, 3); } diff --git a/components/rangeslider/script.js b/components/rangeslider/script.js index aa7b4d9cf..a46a2e3bd 100644 --- a/components/rangeslider/script.js +++ b/components/rangeslider/script.js @@ -4,12 +4,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import BasicRangeSlider from './rangesliders/singleHandleSliders/basicRangeslider'; -import ValuesRangeSlider from './rangesliders/singleHandleSliders/valuesRangeslider'; -import BasicTwoHandlesRangeSlider from './rangesliders/twoHandlesSliders/basicTwoHandlesRangeSlider'; -import { checkOrientation } from './rangesliders/rangeSliderUtils'; +import { components } from '../../lib/components.js'; +// const components = new Components(); +import BasicRangeSlider from './rangesliders/singleHandleSliders/basicRangeslider.js'; +import ValuesRangeSlider from './rangesliders/singleHandleSliders/valuesRangeslider.js'; +import BasicTwoHandlesRangeSlider from './rangesliders/twoHandlesSliders/basicTwoHandlesRangeSlider.js'; +import { checkOrientation } from './rangesliders/rangeSliderUtils.js'; const RANGE_SLIDERS_TYPES = { BASIC: 'basic', diff --git a/components/scrollable-container/index copy.html b/components/scrollable-container/index copy.html new file mode 100644 index 000000000..73a1cc1d0 --- /dev/null +++ b/components/scrollable-container/index copy.html @@ -0,0 +1,147 @@ + + + + + + + + +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eu urna tempus, ultricies lacus fermentum, posuere + arcu. Ut eget elit magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse feugiat + auctor finibus. Ut in euismod magna. Fusce eget dapibus arcu. Curabitur laoreet elit id lobortis tristique. Sed + vel finibus turpis. Nulla sed lectus ante. Sed rutrum libero odio, non congue erat hendrerit non. Nunc in + vulputate dolor, et dapibus neque. Sed accumsan sapien fermentum facilisis pharetra. Pellentesque fermentum, + ligula faucibus suscipit elementum, erat ante ullamcorper tortor, id cursus mi eros ut lorem. + Mauris condimentum leo vitae leo vehicula tincidunt. Quisque vehicula erat elit. Donec commodo bibendum ipsum + vel commodo. Curabitur egestas massa sed purus dapibus commodo. Nam auctor tempus lacus, quis eleifend ipsum + faucibus id. Nunc ullamcorper velit in lorem ultrices, eu auctor ante euismod. Donec in congue lacus. Quisque + erat nibh, viverra sit amet ultrices eu, imperdiet ut lectus. + Integer pellentesque convallis nibh id viverra. Nam consequat rhoncus placerat. Donec velit tortor, malesuada et + scelerisque ut, commodo sit amet purus. Proin nec enim ultricies mi vulputate dignissim. Integer varius augue + vel tortor semper, non tempor lectus tempor. Aenean ac iaculis lacus, vel placerat nunc. Praesent rhoncus nisi + vel tortor sollicitudin, ut sollicitudin nunc cursus. Suspendisse fringilla magna non sapien commodo, et + vulputate erat volutpat. Aenean suscipit pulvinar faucibus. Nullam semper porta purus vitae efficitur. Sed id + pharetra ligula, eget aliquet libero. Duis eleifend blandit lorem sed hendrerit. Nulla volutpat dapibus aliquam. + Vestibulum vehicula elementum dui id maximus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices + posuere cubilia curae; Proin aliquam pretium cursus. Vivamus in gravida odio, eu pulvinar quam. Sed sit amet + elementum neque. Fusce dui dolor, laoreet a eros a, hendrerit ultricies nibh. Suspendisse aliquam magna diam, + quis porttitor diam dictum viverra. Sed in lacus tincidunt, sodales quam non, dapibus lacus. Phasellus + scelerisque velit elit, eget hendrerit ipsum lacinia eu. Aliquam vitae sem et mauris molestie porttitor. + Vestibulum in convallis lectus. Nam at turpis eget mauris gravida ullamcorper. Sed metus ex, semper eget quam + vitae, pellentesque gravida lectus. Etiam condimentum sit amet felis ac tempor. Duis finibus accumsan justo, id + dictum purus ornare at. Mauris congue elementum pellentesque. Quisque vel tempor ipsum. Mauris dignissim + suscipit ex vel posuere. Fusce mattis tortor in cursus feugiat. Duis consequat sem non tempor fringilla. Duis ac + orci velit. Curabitur et sem elit. Nam enim nisl, pellentesque in rutrum a, tincidunt vitae augue. Orci varius + natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aliquam nunc tellus, ultricies vel + vehicula ac, ultrices nec ipsum. Integer luctus vitae nunc quis sollicitudin. Proin id ipsum dapibus urna + aliquet vulputate. Curabitur consequat tincidunt massa non condimentum. Sed at lobortis metus. Donec sed elit + sit amet orci lacinia sagittis nec ac sapien. Etiam convallis nibh nec tellus mattis, in sagittis enim posuere. + Pellentesque et pharetra diam. Integer lacinia dapibus felis, id ornare tellus pellentesque a. Quisque venenatis + ligula sed nisl faucibus, non ornare quam porta. Nullam vitae luctus nibh. Duis quis consectetur urna. Vivamus + elementum id nulla eu viverra. In maximus, libero ac placerat blandit, metus risus pretium augue, sed porta nunc + risus ac justo. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas + interdum eleifend convallis. Aliquam erat volutpat. Aliquam ac efficitur odio. Sed sit amet ex eget nibh + volutpat maximus vitae facilisis dui. Cras vitae egestas nisi. In hac habitasse platea dictumst. Integer eget + leo in enim gravida rhoncus vitae ut sapien. Donec eget sapien est. Sed sapien lacus, feugiat sed nibh at, + luctus tempus velit. Nulla vel imperdiet nibh, at sodales lacus. Proin in consequat lacus. Suspendisse eu + ullamcorper nisl. Donec arcu enim, fermentum vitae elementum vel, cursus tincidunt metus. Nulla aliquam enim + quis sagittis dictum. Praesent venenatis sed elit non lobortis. Mauris sodales rutrum volutpat. Suspendisse eget + sem et enim varius cursus quis in lectus. Fusce libero sapien, tincidunt sit amet pellentesque nec, consequat + vel dolor. Quisque sit amet nibh suscipit justo scelerisque vehicula at in augue. Ut tincidunt blandit erat sed + tincidunt. Maecenas imperdiet eleifend vulputate. Vivamus sit amet est suscipit, ornare tortor a, sagittis nibh. + Quisque pretium vulputate bibendum. Proin interdum tortor vitae urna facilisis feugiat. In tincidunt enim massa, + sit amet laoreet nisl aliquet et. Suspendisse quam turpis, egestas vitae efficitur et, hendrerit nec sem. Nullam + commodo neque ipsum, vel iaculis mauris facilisis vel. Suspendisse at magna ut libero ornare tempor in non ex. + Aenean maximus dictum turpis, et rutrum sapien elementum a. Nulla convallis ipsum ut efficitur convallis. + Suspendisse suscipit iaculis scelerisque. Nunc eu dui augue. Duis nec pellentesque odio, a iaculis lacus. Morbi + venenatis nibh lacus, quis molestie ante finibus in. Etiam scelerisque magna quis feugiat ultricies. Cras + euismod massa sed risus aliquam eleifend. Phasellus finibus augue ac rhoncus mattis. Sed commodo erat quis urna + faucibus facilisis. Cras sit amet risus nec nunc dignissim porttitor nec sit amet ligula. Mauris tincidunt + cursus eros, in convallis magna ultricies eu. Donec ut faucibus ligula. In vitae dui dolor. Suspendisse varius + non nisi id auctor. Suspendisse et ligula at elit vulputate commodo. Fusce aliquam sagittis orci, quis porta + tellus. Donec nunc leo, viverra facilisis ante quis, tincidunt sagittis orci. Aliquam feugiat tincidunt posuere. + Morbi nibh neque, lacinia ut semper id, efficitur quis mauris. Aliquam accumsan elit nec leo elementum, volutpat + consectetur orci tempus. Pellentesque consectetur dapibus ante quis condimentum. Vestibulum tellus ex, pretium + quis auctor id, fermentum a nisl. Suspendisse potenti. Mauris tristique, felis eget tempus maximus, eros lorem + vestibulum risus, ac viverra enim est nec tortor. Aenean velit urna, molestie scelerisque neque eget, viverra + facilisis enim. Etiam cursus venenatis velit, eleifend ultrices felis molestie eget. Etiam congue vehicula dui, + molestie sagittis massa cursus sed. Nunc congue accumsan est at suscipit. Sed ut congue massa. Nulla non dui + quis velit interdum pharetra. Proin posuere bibendum nibh non tincidunt. Phasellus id lectus lacus. In hac + habitasse platea dictumst. Etiam placerat consequat scelerisque. Praesent vitae risus at felis laoreet congue. + Donec rhoncus lacus eget dignissim convallis. Duis nisl neque, ultricies euismod nisl et, sagittis congue urna. + Fusce rhoncus elit sit amet tellus convallis tempus. Etiam malesuada varius ex, sit amet feugiat sapien rutrum + quis. Mauris at turpis cursus, vestibulum sem nec, consectetur libero. Morbi rutrum varius elementum. Proin + scelerisque purus in libero laoreet, nec interdum sapien condimentum. Aliquam imperdiet ligula nec leo elementum + pharetra. Quisque ac libero id nisi lobortis efficitur. Aliquam erat volutpat. Donec consectetur suscipit arcu + sit amet posuere. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. + Pellentesque pulvinar sollicitudin odio a semper. Sed consectetur dui vel nisl egestas, et aliquam est iaculis. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus eget sodales lorem. Phasellus at pharetra ex, + nec euismod massa. Cras sollicitudin interdum dignissim. Aliquam commodo efficitur posuere. Quisque et dolor in + quam vulputate semper. Suspendisse euismod fermentum dictum. Sed pretium diam lacus. Sed sed erat tempor, + gravida sem id, facilisis nibh. Aenean scelerisque urna non fermentum laoreet. Quisque faucibus lacinia sapien + elementum faucibus. Duis id lorem a magna mollis efficitur. Integer venenatis eget leo nec viverra. Etiam ac + felis sollicitudin, venenatis erat molestie, blandit ante. Aenean volutpat arcu enim, in ultrices arcu suscipit + ac. Curabitur porta venenatis maximus. Vivamus sed viverra ipsum, nec posuere elit. Morbi placerat egestas + massa, non convallis sem dignissim sit amet. Quisque arcu ex, auctor at elit non, dignissim vulputate lorem. + Mauris pulvinar in est vitae consequat. Mauris volutpat justo non ligula malesuada, et porttitor dui auctor. + Cras sit amet ex volutpat, aliquam mauris quis, aliquam justo. Praesent non orci nec dui bibendum faucibus + porttitor sed elit. Praesent lobortis lacus nec erat commodo, ut lobortis dolor lobortis. Mauris rhoncus arcu + vel nisl fringilla pellentesque. Pellentesque sit amet nunc convallis, tincidunt neque vel, elementum dolor. + Quisque sit amet imperdiet quam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac + turpis egestas. Morbi ultricies tellus dolor, ac rhoncus nulla posuere ac. Sed rutrum consequat condimentum. In + at lacus est. Ut varius mi nunc. Proin aliquet justo lacus. Etiam ut mauris lacinia, placerat purus eget, + elementum felis. Aliquam commodo ac tortor nec elementum. Nulla imperdiet erat nec justo tristique laoreet. + Vivamus quis eros gravida, dignissim ante in, scelerisque tellus. Aenean euismod hendrerit ex vel porta. Nunc ac + nisl eros. Morbi efficitur lorem lectus, in rhoncus purus tempor vel. Phasellus id mi placerat, venenatis dui + eu, sagittis risus. Ut ac ornare leo. Duis condimentum lorem ut est scelerisque malesuada. Etiam varius ornare + libero, nec consequat magna tristique porttitor. Cras dapibus, augue vel hendrerit fermentum, nibh lectus + venenatis dui, quis porta odio lorem dignissim lacus. Aliquam tempor eros et volutpat tincidunt. Vestibulum vel + sagittis libero, pretium iaculis enim. Etiam libero nulla, consequat quis nunc id, viverra condimentum turpis. + Nulla facilisi. Mauris sit amet auctor justo. Ut faucibus erat a ornare malesuada. Duis a justo pharetra, + ullamcorper lacus quis, iaculis lectus. Morbi dapibus nisl mauris, ac tincidunt est vehicula eu. Suspendisse + purus risus, efficitur ac rhoncus eu, congue vel ipsum. Ut pharetra tristique feugiat. Pellentesque habitant + morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam ut rutrum massa. Suspendisse + tincidunt tempor mauris, vitae auctor nisl viverra quis. Quisque vitae bibendum turpis. Morbi ut lectus eros. + Aliquam sed quam vitae risus semper bibendum vitae pretium augue. Integer rhoncus consectetur orci eget mollis. + Vestibulum cursus ut leo vitae sagittis. Integer pretium eu lorem vel elementum. Nunc vehicula sit amet augue + ultrices commodo. Cras in ornare est. Cras tristique luctus nibh, non lacinia orci pretium nec. Integer a ligula + non velit dignissim facilisis nec ut lectus. Maecenas eget lobortis lectus. Ut pretium mi in purus interdum, ut + mattis tortor vulputate. Nunc eu blandit magna, nec efficitur augue. Etiam ac hendrerit sapien. Vestibulum ante + ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam eu gravida lorem. Phasellus + accumsan porta lacinia. Nam eu augue non dolor consectetur hendrerit vitae non massa. Etiam commodo vel dolor eu + vestibulum. Ut euismod tempus urna, et commodo nibh varius sit amet. Nam posuere ornare faucibus. In hac + habitasse platea dictumst. Integer elit tellus, vehicula nec odio ac, efficitur ultricies nunc. Sed laoreet + volutpat facilisis. Integer orci massa, posuere sed enim ut, vulputate viverra ex. Mauris consectetur turpis ac + porta interdum. Nam eu porta leo. + Nam at justo enim. Nam dictum facilisis mattis. Orci varius natoque penatibus et magnis dis parturient montes, + nascetur ridiculus mus. Fusce eget blandit ex, nec elementum erat. Vivamus purus purus, bibendum quis hendrerit + sed, vehicula vitae arcu. Nam enim ligula, rutrum vitae imperdiet vitae, tristique id urna. Aenean rutrum sed + nunc vel ultricies. Suspendisse iaculis, dolor vel blandit blandit, lacus tellus sodales nulla, id aliquam est + nisl eu ligula. Nulla fermentum neque quis metus tristique scelerisque. Nulla aliquam vel libero sit amet + mollis. Nulla ut consequat nisl. Proin eu dignissim nisi. +
+
+ + + + \ No newline at end of file diff --git a/components/scrollable-container/index.html b/components/scrollable-container/index.html index 4465f13c1..d8bd0c412 100644 --- a/components/scrollable-container/index.html +++ b/components/scrollable-container/index.html @@ -3,9 +3,9 @@ - - - + + +
+
+ +
+ +
+`; + + this.setup(); + this.scrollbar.style.visibility = 'hidden'; + this.shouldShowScrollbar(); + if (this.automatic) this.initMutationObserver(); + this.isRendered = true; + // }); } /** @@ -146,9 +196,10 @@ class ScrollableContainer extends BaseComponent { this.shouldShowScrollbarCallback = this.shouldShowScrollbarCallback.bind(this); // load the template - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); + this.init(); } /** @@ -158,7 +209,7 @@ class ScrollableContainer extends BaseComponent { if (this.observer) this.removeMutationObserver(); this.observer = new ResizeObserver(this.shouldShowScrollbar); - const scrollableContent = this.querySelector('[data-name="scrollable-content"]'); + const scrollableContent = this.shadowRoot.querySelector('slot[name="scrollable-content"]'); this.observer.observe(scrollableContent); this.observer.observe(this); @@ -176,9 +227,9 @@ class ScrollableContainer extends BaseComponent { * Set the scrollableContainer and scrollbar members and attach event listeners. */ setup() { - this.scrollableContainer = this.getElementsByClassName('guic-scrollable-container')[0]; - this.scrollbar = this.getElementsByClassName('guic-slider-component')[0]; - if (!components.isBrowserGameface()) this.scrollableContainer.classList.add('guic-native-scroll-disabled'); + this.scrollableContainer = this.shadowRoot.querySelector('.guic-scrollable-container'); + this.scrollbar = this.shadowRoot.querySelector('.guic-slider-component'); + // if (!components.isBrowserGameface()) this.scrollableContainer.classList.add('guic-native-scroll-disabled'); this.addEventListeners(); } @@ -219,6 +270,7 @@ class ScrollableContainer extends BaseComponent { * Called on scroll event of the scrollable container. */ onScroll() { + console.log('a'); // get the scroll position in percents this.scrollPos = (this.scrollableContainer.scrollTop / this.scrollableContainer.scrollHeight) * 100; } @@ -245,7 +297,14 @@ class ScrollableContainer extends BaseComponent { * For example this.scrollableContainer.classList.add('some-class'). */ shouldShowScrollbar() { - components.waitForFrames(this.shouldShowScrollbarCallback); + // components.waitForFrames(this.shouldShowScrollbarCallback); + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + this.shouldShowScrollbarCallback(); + }); + }); + }); } /** @@ -253,7 +312,7 @@ class ScrollableContainer extends BaseComponent { * @returns {void} */ shouldShowScrollbarCallback() { - const scrollableContent = this.querySelector('[data-name="scrollable-content"]'); + const scrollableContent = this.shadowRoot.querySelector('slot[name="scrollable-content"]'); const scrollableContentRect = scrollableContent.getBoundingClientRect(); const boundingRect = this.getBoundingClientRect(); if (scrollableContentRect.height <= boundingRect.height) { @@ -275,25 +334,25 @@ class ScrollableContainer extends BaseComponent { /** * Will add styles for the non Coherent browsers that are disabling the native scrollbar */ -function addDisabledNativeScrollbarStyles() { - const style = document.createElement('style'); - style.innerHTML = ` - .guic-native-scroll-disabled { - -ms-overflow-style: none; - scrollbar-width: none; - } - .guic-native-scroll-disabled::-webkit-scrollbar { - display: none; - }`; - document.head.appendChild(style); -} - -if (!components.isBrowserGameface() && !components.nativeScrollDisabledStylesAdded) { - addDisabledNativeScrollbarStyles(); - // We are doing this to prevent readdition of the styles needed for the native scrollbar to not be visible. - // This problem is produced when multiple components have the scrollable container bundled. - components.nativeScrollDisabledStylesAdded = true; -} - -components.defineCustomElement('gameface-scrollable-container', ScrollableContainer); -export default ScrollableContainer; +// function addDisabledNativeScrollbarStyles() { +// const style = document.createElement('style'); +// style.innerHTML = ` +// .guic-native-scroll-disabled { +// -ms-overflow-style: none; +// scrollbar-width: none; +// } +// .guic-native-scroll-disabled::-webkit-scrollbar { +// display: none; +// }`; +// document.head.appendChild(style); +// } + +// if (!components.isBrowserGameface() && !components.nativeScrollDisabledStylesAdded) { +// addDisabledNativeScrollbarStyles(); +// // We are doing this to prevent readdition of the styles needed for the native scrollbar to not be visible. +// // This problem is produced when multiple components have the scrollable container bundled. +// components.nativeScrollDisabledStylesAdded = true; +// } + +customElements.define('gameface-scrollable-container', ScrollableContainer); +// export default ScrollableContainer; diff --git a/components/scrollable-container/slider.js b/components/scrollable-container/slider.js new file mode 100644 index 000000000..75e2b101c --- /dev/null +++ b/components/scrollable-container/slider.js @@ -0,0 +1,527 @@ +/* eslint-disable linebreak-style */ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coherent Labs AD. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// import { Components } from 'coherent-gameface-components'; +// const components = new Components(); +// import verticalTemplate from './templates/vertical.html'; +// import horizontalTemplate from './templates/horizontal.html'; +// import { orientationUnitsNames } from './orientationUnitsNames'; + +const orientationUnitsNames = new Map([ + ['vertical', { + mouseAxisCoords: 'clientY', + size: 'height', + sizePX: 'heightPX', + position: 'top', + scroll: 'scrollHeight', + offset: 'offsetHeight', + }], + ['horizontal', { + mouseAxisCoords: 'clientX', + size: 'width', + sizePX: 'widthPX', + position: 'left', + scroll: 'scrollWidth', + offset: 'offsetWidth', + }], +]); +// const BaseComponent = components.BaseComponent; +const template = ` + + +
+
+
+
+
+
+
+
+
+
+
`; +/** + * Slider component; can be independently or as a building block of another + * component - for example a scrollbar. This is a custom slider control, do not + * confuse with the standard input type slider HTML element. +*/ +class Slider extends HTMLElement { + // eslint-disable-next-line require-jsdoc + static get observedAttributes() { return ['step', 'orientation']; } + + /** + * Set the position of the slider's handler. + * @param {number} value - the new value in percents. + */ + set handlePosition(value) { + this._handlePosition = value; + // The names of the units vary depending on the orientation + // of the slider - width for horizontal, height for vertical etc. + this.handle.style[this.units.position] = value + '%'; + } + + /** + * Get the current position of the slider's handle in percents. + * @returns {number} - the value of the position. + */ + get handlePosition() { + return this._handlePosition; + } + + /** + * Get the current position of the slider's handle in pixels. + * @returns {number} - the value of the position. + */ + get handlePositionPx() { + const sliderSize = this.slider[this.units.offset]; + return this.handlePosition / 100 * sliderSize; + } + + // eslint-disable-next-line require-jsdoc + get step() { return this.state.step; } + + // eslint-disable-next-line require-jsdoc + set step(value) { this.setAttribute('step', value); } + + // eslint-disable-next-line require-jsdoc + get orientation() { return this.state.orientation; } + + // eslint-disable-next-line require-jsdoc + set orientation(value) { this.setAttribute('orientation', value); } + + // eslint-disable-next-line require-jsdoc + constructor() { + super(); + + this.onSlideUp = (e) => { this.onSlideWithArrorws(-1); }; + this.onSlideDown = (e) => { this.onSlideWithArrorws(1); }; + this.onClick = this.onClick.bind(this); + this.onWheel = this.onWheel.bind(this); + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseMove = this.onMouseMove.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + this.init = this.init.bind(this); + + this.state = { + orientation: 'vertical', + step: 10, + }; + + this.stateSchema = { + orientation: { type: ['string'] }, + step: { type: ['number'] }, + }; + } + + /** + * Custom element lifecycle method. Called when an attribute is changed. + * @param {string} name + * @param {string} oldValue + * @param {string|boolean} newValue + */ + attributeChangedCallback(name, oldValue, newValue) { + if (!this.isRendered) return; + + this.updateAttributeState(name, oldValue, newValue); + } + + /** + * Will update the state properties + * @param {string} name + * @param {string} oldValue + * @param {string} value + */ + updateAttributeState(name, oldValue, value) { + // Prevent state updates if the value is the same especially when orientation is changed because then the whole component will be re-rendered + if (oldValue === value) return; + + switch (name) { + case 'step': + this.updateState('step', parseFloat(value)); + break; + case 'orientation': + this.updateOrientationState(value); + break; + } + } + + /** + * Update the slider's state. + * @param {string} name - the name of the prop + * @param {string | boolean} value - the value of the the prop + * @returns {void} + */ + updateState(name, value) { + if (!this.isStatePropValid(name, value)) return; + this.state[name] = value; + } + + /** + * Will update the slider when orientation attribute is changed + * @param {boolean} value + */ + updateOrientationState(value) { + this.checkOrientationValueValidity(value); + this.reRender(); + } + + /** + * Will verify that the orientation has valid value and will fallback if not + * @param {string} value + */ + checkOrientationValueValidity(value) { + if (!['vertical', 'horizontal'].includes(value)) { + console.warn(`'${value}' is not a valid orientation. It should be either 'horizontal' or 'vertical'. Will fallback to 'vertical'`); + } + } + + /** + * Will re-render the component from scratch + */ + reRender() { + this.template = undefined; + this.isRendered = false; + this.connectedCallback(); + } + + /** + * Initialize the custom component. + * Set template, attach event listeners, setup initial state etc. + * @param {object} data + */ + init(data) { + // this.setupTemplate(data, () => { + // render the template + // components.renderOnce(this); + // do the initial setup - add event listeners, assign members + // }); + } + + + /** + * Called when the element was attached to the DOM. + */ + connectedCallback() { + // the amount of units that the slider will be updated + this.state.step = this.getAttribute('step') || 10; + // the initial position of the handle + this._handlePosition = 0; + + // vertical or horizontal + this.state.orientation = this.getAttribute('orientation'); + if (!['vertical', 'horizontal'].includes(this.orientation)) this.state.orientation = 'vertical'; + // use the template for the current slider orientation + this.template = (this.orientation === 'vertical') ? template : template; + /** + * The names of the units are different for the two slider types. + * ['clientY', 'height', 'heightPX', 'top', 'scrollHeight] for vertical and + * ['clientX', 'width', 'widthPX', 'left', 'scrollWidth] for horizontal + */ + this.units = orientationUnitsNames.get(this.orientation); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = template; + this.setup(); + + // Load the template + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); + } + + /** + * Set the slider and handle members and add event listeners. + */ + setup() { + this.slider = this.shadowRoot.querySelector(`.guic-slider-${this.orientation}-slider`); + this.handle = this.shadowRoot.querySelector(`.guic-slider-${this.orientation}-handle`); + + this.attachEventListeners(); + } + + // eslint-disable-next-line require-jsdoc + disconnectedCallback() { + this.removeEventListeners(); + } + /** + * Gets the size of an element in px. + * @param {HTMLElement} element + * @returns {number} - the size in pixels. + */ + getElementSize(element) { + const unitsName = this.units.offset; + return element[unitsName]; + } + + /** + * Update the size of the slider thumb. + * This function is used from within the Scrollable Container Component only. + * @param {HTMLElement} scrollableContainer + */ + resize(scrollableContainer) { + const sliderWrapper = this.shadowRoot.querySelector(`.guic-${this.orientation}-slider-wrapper`); + let scrollableContainerComponent = null; + // We do it like that because in Gameface such syntax - scrollableContainer?.parentElement?.parentElement; is not woking + if (scrollableContainer && scrollableContainer.parentElement) { + scrollableContainerComponent = scrollableContainer.parentElement; + } + if (scrollableContainerComponent && scrollableContainerComponent.parentElement) { + scrollableContainerComponent = scrollableContainerComponent.parentElement; + } + + const scrollableContainerSize = this.getElementSize(scrollableContainer); + if (scrollableContainerComponent.tagName === 'GAMEFACE-SCROLLABLE-CONTAINER' && !scrollableContainerComponent.hasAttribute('fixed-slider-height')) { + // set the slider wrapper to be as big as the scrollable container + sliderWrapper.style.height = `${scrollableContainerSize}px`; + } else { + // remove height property from the slider if the fixed-slider-height attribute is set dynamically + sliderWrapper.style.height = ''; + } + + // Wait 1 layout frame so the the new slider height has taken effect set from the prev lines + // components.waitForFrames(() => { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + // get the size of the slider area + const sliderSize = this.slider[this.units.offset]; + // get the size of the handle in percents relative to the current scroll(Height/Width) + const handleSizePercent = (sliderSize / scrollableContainer[this.units.scroll]) * 100; + // get the size of the handle in px; + const handleSize = (scrollableContainerSize / 100) * handleSizePercent; + // set the new size of the handle + this.handle.style[this.units.size] = handleSize + 'px'; + + this.scrollTo(this.handlePositionPx); + if (this.style.visibility === 'hidden') this.style.visibility = 'visible'; + }); + }); + }); + + // }); + } + + /** + * Remove event listeners. + */ + removeEventListeners() { + // document listeners + document.removeEventListener('mousemove', this.onMouseMove); + document.removeEventListener('mouseup', this.onMouseUp); + } + + /** + * Add event listeners to handle user interaction. + */ + attachEventListeners() { + // local listeners + this.slider.addEventListener('click', this.onClick); + this.slider.addEventListener('wheel', this.onWheel); + this.handle.addEventListener('mousedown', this.onMouseDown); + this.shadowRoot.querySelector('.up').addEventListener('mousedown', this.onSlideUp); + this.shadowRoot.querySelector('.down').addEventListener('mousedown', this.onSlideDown); + + // document listeners + document.addEventListener('mousemove', this.onMouseMove); + document.addEventListener('mouseup', this.onMouseUp); + } + + /** + * Executed on mousedown. Moves the handle towards the position of the mouse + * with one step. + * @param {MouseEvent} event + */ + onMouseDown(event) { + // set a flag to help the detection of drag + this.mousedown = true; + // get the bounding rectangles of the slider area and the handle + const handleRect = this.handle.getBoundingClientRect(); + const sliderRect = this.slider.getBoundingClientRect(); + + // get the current position of the slider (top or left) + const sliderY = sliderRect[this.units.position]; + // get the handle position within the slider's coordinates + const handleY = handleRect[this.units.position] - sliderY; + const mouseY = event[this.units.mouseAxisCoords] - sliderY; + + // set the difference between the mouse click and the handle position + // used for better looking drag + this.delta = mouseY - handleY; + } + + /** + * Called on mouseup. + * Resets the mousedown, dragging and slidingWithArrows properties + * and clears intervals. + */ + onMouseUp() { + this.mousedown = false; + this.dragging = false; + + if (this.slidingWithArrows) { + this.slidingWithArrows = false; + clearInterval(this.interval); + } + } + + /** + * Called on mousemove. + * Detects dragging and scrolls to the current position of the mouse. + * @param {MouseEvent} event + */ + onMouseMove(event) { + if (!this.mousedown) return; + this.dragging = true; + const sliderRect = this.slider.getBoundingClientRect(); + // get the mouse position within the slider coordinates + const mouseY = event[this.units.mouseAxisCoords] - sliderRect[this.units.position]; + this.scrollTo(mouseY - this.delta); + } + + /** + * Called when the arrow controls are used for sliding. + * Starts an interval and updates the slider position until mouseup occurs. + * @param {number} direction - 1 for down, -1 for up + */ + onSlideWithArrorws(direction) { + this.slidingWithArrows = true; + this.interval = setInterval(() => this.scrollTo(this.getNextScrollPosition(direction, this.step)), 10); + } + + /** + * Scrolls the a given position in percents. + * Used from the scrollable container + * @param {number} position + */ + scrollToPercents(position) { + const handleRect = this.handle.getBoundingClientRect(); + const sliderRect = this.slider.getBoundingClientRect(); + const handleSizePercent = (handleRect[this.units.size] / sliderRect[this.units.size]) * 100; + + // the slider range in percents is [0 - 100 - handleSizePercent] + // if the new position is outside of this range - snap the handle and + // scroll to the top or to the bottom + if (position < 0) position = 0; + if (position + handleSizePercent > 100) position = 100 - handleSizePercent; + this.handlePosition = position; + } + + /** + * Scrolls the a given position. + * @param {number} position + */ + scrollTo(position) { + const handleRect = this.handle.getBoundingClientRect(); + const sliderRect = this.slider.getBoundingClientRect(); + + const handleSizePercent = (handleRect[this.units.size] / sliderRect[this.units.size]) * 100; + // new position in % + let newPosPercents = (position / sliderRect[this.units.size]) * 100; + + // the slider range in percents is [0 - 100 - handleSizePercent] + // if the new position is outside of this range - snap the handle and + // scroll to the top or to the bottom + if (newPosPercents < 0) newPosPercents = 0; + if (newPosPercents + handleSizePercent > 100) newPosPercents = 100 - handleSizePercent; + this.handlePosition = newPosPercents; + + // dispatch an event in case something needs to be done on scroll + this.dispatchEvent(new CustomEvent('slider-scroll', { detail: { handlePosition: newPosPercents } })); + } + + /** + * Called on wheel event of the mouse. + * Scrolls the slider in the position of which the wheel is rotated + * @param {WheelEvent} event + */ + onWheel(event) { + const direction = (event.deltaY < 0) ? -1 : 1; + this.scrollTo(this.getNextScrollPosition(direction, this.step)); + } + + /** + * Called on click of the mouse. + * Updated the handle's position with one step towards the position of the + * mouse click. + * @param {MouseEvent} event + */ + onClick(event) { + if (event.target.classList.contains('handle')) return; + let direction = -1; + if (this.handle.getBoundingClientRect()[this.units.position] < event[this.units.mouseAxisCoords]) direction = 1; + this.scrollTo(this.getNextScrollPosition(direction, this.step)); + } + + /** + * Gets the next value of the scroll. + * @param {number} direction + * @param {number} step + * @returns {number} - the new scroll position + */ + getNextScrollPosition(direction, step = this.step) { + // get the current scroll postition in px + const scrollTop = this.handlePosition * this.slider.getBoundingClientRect()[this.units.size] / 100; + return scrollTop + (direction * step); + } +} + +customElements.define('gameface-slider', Slider); +// export default Slider; diff --git a/components/scrollable-container/template.html b/components/scrollable-container/template.html deleted file mode 100644 index 1da3a7ed8..000000000 --- a/components/scrollable-container/template.html +++ /dev/null @@ -1,7 +0,0 @@ - -
-
- -
- -
diff --git a/components/slider/index.html b/components/slider/index.html index 6685dc93a..a5f6863b3 100644 --- a/components/slider/index.html +++ b/components/slider/index.html @@ -1,43 +1,71 @@ - - - - - - - -
-

Blur: 0

-
- -
-
-
-
- -

Hue Rotate: 0

+ .flex-container { + display: flex; + } + + .avatar { + width: 30vh; + height: 40vh; + background-size: contain; + background-repeat: no-repeat no-repeat; + background-image: url(./demo/images/avatar.png); + } + + + + +
+

Blur: 0

+
+ +
- - +
+
+ +

Hue Rotate: 0

+
+ + + + + \ No newline at end of file diff --git a/components/slider/script.js b/components/slider/script.js index 38649fbdc..931c28474 100644 --- a/components/slider/script.js +++ b/components/slider/script.js @@ -4,20 +4,179 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import verticalTemplate from './templates/vertical.html'; -import horizontalTemplate from './templates/horizontal.html'; -import { orientationUnitsNames } from './orientationUnitsNames'; +// import { Components } from 'coherent-gameface-components'; +// const components = new Components(); +// import verticalTemplate from './templates/vertical.html'; +// import horizontalTemplate from './templates/horizontal.html'; +import { orientationUnitsNames } from './orientationUnitsNames.js'; + +// const orientationUnitsNames = new Map([ +// ['vertical', { +// mouseAxisCoords: 'clientY', +// size: 'height', +// sizePX: 'heightPX', +// position: 'top', +// scroll: 'scrollHeight', +// offset: 'offsetHeight', +// }], +// ['horizontal', { +// mouseAxisCoords: 'clientX', +// size: 'width', +// sizePX: 'widthPX', +// position: 'left', +// scroll: 'scrollWidth', +// offset: 'offsetWidth', +// }], +// ]); +// const BaseComponent = components.BaseComponent; +const templateHorizontal = ` + +
+
+
+
+
+
+
+
+
+
+
+`; +const templateVertical = ` + + +
+
+
+
+
+
+
+
+
+
+
`; /** * Slider component; can be independently or as a building block of another * component - for example a scrollbar. This is a custom slider control, do not * confuse with the standard input type slider HTML element. */ -class Slider extends BaseComponent { +class Slider extends HTMLElement { // eslint-disable-next-line require-jsdoc static get observedAttributes() { return ['step', 'orientation']; } @@ -162,12 +321,11 @@ class Slider extends BaseComponent { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - // render the template - components.renderOnce(this); - // do the initial setup - add event listeners, assign members - this.setup(); - }); + // this.setupTemplate(data, () => { + // render the template + // components.renderOnce(this); + // do the initial setup - add event listeners, assign members + // }); } @@ -184,26 +342,29 @@ class Slider extends BaseComponent { this.state.orientation = this.getAttribute('orientation'); if (!['vertical', 'horizontal'].includes(this.orientation)) this.state.orientation = 'vertical'; // use the template for the current slider orientation - this.template = (this.orientation === 'vertical') ? verticalTemplate : horizontalTemplate; + this.template = (this.orientation === 'vertical') ? templateVertical : templateHorizontal; /** * The names of the units are different for the two slider types. * ['clientY', 'height', 'heightPX', 'top', 'scrollHeight] for vertical and * ['clientX', 'width', 'widthPX', 'left', 'scrollWidth] for horizontal */ this.units = orientationUnitsNames.get(this.orientation); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.setup(); // Load the template - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /** * Set the slider and handle members and add event listeners. */ setup() { - this.slider = this.getElementsByClassName(`guic-slider-${this.orientation}-slider`)[0]; - this.handle = this.getElementsByClassName(`guic-slider-${this.orientation}-handle`)[0]; + this.slider = this.shadowRoot.querySelector(`.guic-slider-${this.orientation}-slider`); + this.handle = this.shadowRoot.querySelector(`.guic-slider-${this.orientation}-handle`); this.attachEventListeners(); } @@ -228,7 +389,7 @@ class Slider extends BaseComponent { * @param {HTMLElement} scrollableContainer */ resize(scrollableContainer) { - const sliderWrapper = this.querySelector(`.guic-${this.orientation}-slider-wrapper`); + const sliderWrapper = this.shadowRoot.querySelector(`.guic-${this.orientation}-slider-wrapper`); let scrollableContainerComponent = null; // We do it like that because in Gameface such syntax - scrollableContainer?.parentElement?.parentElement; is not woking if (scrollableContainer && scrollableContainer.parentElement) { @@ -248,19 +409,25 @@ class Slider extends BaseComponent { } // Wait 1 layout frame so the the new slider height has taken effect set from the prev lines - components.waitForFrames(() => { - // get the size of the slider area - const sliderSize = this.slider[this.units.offset]; - // get the size of the handle in percents relative to the current scroll(Height/Width) - const handleSizePercent = (sliderSize / scrollableContainer[this.units.scroll]) * 100; - // get the size of the handle in px; - const handleSize = (scrollableContainerSize / 100) * handleSizePercent; - // set the new size of the handle - this.handle.style[this.units.size] = handleSize + 'px'; - - this.scrollTo(this.handlePositionPx); - if (this.style.visibility === 'hidden') this.style.visibility = 'visible'; + // components.waitForFrames(() => { + // get the size of the slider area + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + const sliderSize = this.slider[this.units.offset]; + // get the size of the handle in percents relative to the current scroll(Height/Width) + const handleSizePercent = (sliderSize / scrollableContainer[this.units.scroll]) * 100; + // get the size of the handle in px; + const handleSize = (scrollableContainerSize / 100) * handleSizePercent; + // set the new size of the handle + this.handle.style[this.units.size] = handleSize + 'px'; + + this.scrollTo(this.handlePositionPx); + if (this.style.visibility === 'hidden') this.style.visibility = 'visible'; + }); + }); }); + // }); } /** @@ -280,8 +447,8 @@ class Slider extends BaseComponent { this.slider.addEventListener('click', this.onClick); this.slider.addEventListener('wheel', this.onWheel); this.handle.addEventListener('mousedown', this.onMouseDown); - this.querySelector('.up').addEventListener('mousedown', this.onSlideUp); - this.querySelector('.down').addEventListener('mousedown', this.onSlideDown); + this.shadowRoot.querySelector('.up').addEventListener('mousedown', this.onSlideUp); + this.shadowRoot.querySelector('.down').addEventListener('mousedown', this.onSlideDown); // document listeners document.addEventListener('mousemove', this.onMouseMove); @@ -427,5 +594,5 @@ class Slider extends BaseComponent { } } -components.defineCustomElement('gameface-slider', Slider); -export default Slider; +customElements.define('gameface-slider', Slider); +// export default Slider; diff --git a/components/slider/styles/vertical.css b/components/slider/styles/vertical.css index cfafd2b15..e737d1e2e 100644 --- a/components/slider/styles/vertical.css +++ b/components/slider/styles/vertical.css @@ -55,10 +55,11 @@ body { top: 0px; left: 0px; width: 100%; + height: 50px; background-color: #c1c1c1; cursor: pointer; } .guic-slider-vertical-handle:hover { background-color: #787878; -} +} \ No newline at end of file diff --git a/components/slider/templates/horizontal.html b/components/slider/templates/horizontal.html index 86e0e3454..ad289d93c 100644 --- a/components/slider/templates/horizontal.html +++ b/components/slider/templates/horizontal.html @@ -1,8 +1,70 @@ +
-
+
+
+
-
-
+
+
+
+
\ No newline at end of file diff --git a/components/slider/templates/vertical.html b/components/slider/templates/vertical.html index 258741825..35d96f57d 100644 --- a/components/slider/templates/vertical.html +++ b/components/slider/templates/vertical.html @@ -1,8 +1,69 @@ +
-
+
+
+
-
-
+
+
+
+
\ No newline at end of file diff --git a/components/stepper/index.html b/components/stepper/index.html index c6bb0f043..fe7ceccd8 100644 --- a/components/stepper/index.html +++ b/components/stepper/index.html @@ -3,7 +3,7 @@ - + +
+
+
+
+
+`; /** * Class description */ @@ -90,6 +157,28 @@ class Stepper extends BaseComponent { if (name === 'value') this.updateValueState(newValue); } + isStatePropValid(name, value) { + const schemaProperty = this.stateSchema[name]; + + if (!schemaProperty) { + console.error(`A property ${name} does not exist on type ${this.tagName.toLowerCase()}!`); + return false; + } + + const type = typeof value; + if (schemaProperty.type.includes('array')) { + const isArray = Array.isArray(value); + if (isArray) return true; + } + + if (!schemaProperty.type.includes(type)) { + console.error(`Property ${name} can not be of type - ${type}. Allowed types are: ${schemaProperty.type.join(',')}`); + return false; + } + + return true; + } + /** * Update the stepper's state. * @param {string} name - the name of the prop @@ -120,34 +209,37 @@ class Stepper extends BaseComponent { } init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - - this.itemElements.forEach(item => this.appendChild(item)); - - this.leftButton = this.querySelector('.guic-stepper-left'); - this.rightButton = this.querySelector('.guic-stepper-right'); - this.valueElement = this.querySelector('.guic-stepper-value'); - const valueAttr = this.getAttribute('value'); - // If there is no `value` attribute then set the stepper value to default - if (valueAttr === null) this.value = this.items[0]; - // Try to update the state with the passed value and if it is invalid set the stepper value to default - else if (!this.updateValueState(valueAttr)) { - console.warn(`Will set the first item from the items array as value - '${this.items[0]}'`); - this.value = this.items[0]; - } - this.attachListeners(); - }); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + + this.itemElements.forEach(item => this.shadowRoot.appendChild(item)); + + this.leftButton = this.shadowRoot.querySelector('.guic-stepper-left'); + this.rightButton = this.shadowRoot.querySelector('.guic-stepper-right'); + this.valueElement = this.shadowRoot.querySelector('.guic-stepper-value'); + const valueAttr = this.getAttribute('value'); + // If there is no `value` attribute then set the stepper value to default + if (valueAttr === null) this.value = this.items[0]; + // Try to update the state with the passed value and if it is invalid set the stepper value to default + else if (!this.updateValueState(valueAttr)) { + console.warn(`Will set the first item from the items array as value - '${this.items[0]}'`); + this.value = this.items[0]; + } + this.attachListeners(); + // }); } connectedCallback() { this.itemElements = Array.from(this.querySelectorAll('gameface-stepper-item')); this._items = this.getItems(); - - components - .loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.init(); + // components + // .loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } disconnectedCallback() { @@ -228,5 +320,5 @@ class Stepper extends BaseComponent { this.value = this.items[this.selectedIndex + 1]; } } -components.defineCustomElement('gameface-stepper', Stepper); +customElements.define('gameface-stepper', Stepper); export default Stepper; diff --git a/components/stepper/template.html b/components/stepper/template.html index cd649ed5b..0f16e7e87 100644 --- a/components/stepper/template.html +++ b/components/stepper/template.html @@ -1,6 +1,65 @@ - + +
-
+ \ No newline at end of file diff --git a/components/switch/index.html b/components/switch/index.html index 60b229982..b7f52e2c0 100644 --- a/components/switch/index.html +++ b/components/switch/index.html @@ -2,7 +2,7 @@ - + +
+
+
+ +
+
+ +
+
+
+
+`; + +const textOutsideTemplate = ` +
+
+ +
+
+
+
+
+ +
+
+`; +/** + * Switch component, that allows you to switch between true and false + */ +class Switch extends CustomElementValidator { + // eslint-disable-next-line require-jsdoc + static get observedAttributes() { return ['checked', 'disabled', 'type']; } + + // eslint-disable-next-line require-jsdoc + get value() { + const value = this.getAttribute('value'); + if (this.isFormElement(this)) return value || 'on'; + return value; + } + + // eslint-disable-next-line require-jsdoc + set value(value) { + this.setAttribute('value', value); + } + + // eslint-disable-next-line require-jsdoc + get name() { + return this.getAttribute('name'); + } + + // eslint-disable-next-line require-jsdoc + set name(value) { + this.setAttribute('name', value); + } + + // eslint-disable-next-line require-jsdoc + get type() { + return this.state.type; + } + + // eslint-disable-next-line require-jsdoc + set type(value) { + this.setAttribute('type', value); + } + + // eslint-disable-next-line require-jsdoc + get disabled() { + return this.state.disabled; + } + + // eslint-disable-next-line require-jsdoc + set disabled(value) { + value ? this.setAttribute('disabled', '') : this.removeAttribute('disabled'); + } + + // eslint-disable-next-line require-jsdoc + get checked() { + return this.state.checked; + } + + // eslint-disable-next-line require-jsdoc + set checked(value) { + value ? this.setAttribute('checked', '') : this.removeAttribute('checked'); + } + + // eslint-disable-next-line require-jsdoc + constructor() { + super(); + + this.onClick = this.onClick.bind(this); + this.init = this.init.bind(this); + + this.stateSchema = { + checked: { type: ['boolean'] }, + disabled: { type: ['boolean'] }, + type: { type: ['string'] }, + }; + + this.state = { + type: '', + checked: false, + disabled: false, + }; + } + + /** + * Custom element lifecycle method. Called when an attribute is changed. + * @param {string} name + * @param {string} oldValue + * @param {string|boolean} newValue + */ + attributeChangedCallback(name, oldValue, newValue) { + if (!this.isRendered) return; + + this.updateAttributeState(name, newValue); + } + + /** + * Will update the state properties linked with the checkbox attributes + * @param {string} name + * @param {string|boolean} value + */ + updateAttributeState(name, value) { + switch (name) { + case 'checked': + this.updateCheckedState(value !== null); + break; + case 'disabled': + this.updateDisabledState(value !== null); + break; + case 'type': + this.reRender(); + break; + } + } + + /** + * Update the checkbox's state. + * @param {string} name - the name of the prop + * @param {string | boolean} value - the value of the the prop + * @returns {void} + */ + updateState(name, value) { + if (!this.isStatePropValid(name, value)) return; + this.state[name] = value; + } + + /** + * Update the switch's disabled state. + * Set relevant styles and tabindex. + * @param {boolean} value + */ + updateDisabledState(value) { + this.updateState('disabled', value); + this.toggleDisabled(value); + } + + /** + * Update the state of the switch and its style + * @param {boolean} value - whether the switch is checked or not + */ + updateCheckedState(value) { + this.updateState('checked', value); + this.dispatchEvent(new CustomEvent('switch_toggle', { detail: value })); + this.toggleClasses(value); + } + + /** + * Initialize the custom component. + * Set template, attach event listeners, setup initial state etc. + * @param {object} data + */ + init(data) { + // this.setupTemplate(data, () => { + // Render the template + // components.renderOnce(this); + + // Set the elements of the switch we'll be changing depending if it's checked or not + this._switch = this.shadowRoot.querySelector('.guic-switch-toggle'); + this._handle = this.shadowRoot.querySelector('.guic-switch-toggle-handle'); + this._textChecked = this.shadowRoot.querySelector('.guic-switch-toggle-true'); + this._textUnchecked = this.shadowRoot.querySelector('.guic-switch-toggle-false'); + this._container = this.shadowRoot.querySelector('.guic-switch-toggle-container'); + this.setup(); + // }); + } + + /** + * Called when the element is attached to the DOM + */ + connectedCallback() { + this.state.disabled = this.hasAttribute('disabled'); + this.state.checked = this.hasAttribute('checked'); + + // The type of the switch. There are currently 3 possible - default, inset and text-inside + this.state.type = this.getAttribute('type'); + + // Helpers for easy readability + this._isDefault = this.state.type !== 'inset' && this.state.type !== 'text-inside'; + this._isInset = this.state.type === 'inset'; + this._isTextInside = this.state.type === 'text-inside'; + + // Set the template based if the text is inside or outside + this.template = this._isTextInside ? textInsideTemplate : textOutsideTemplate; + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.init(); + // Load the template + // components + // .loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); + } + + /** + * Will re-render the rangeslider from scratch + */ + reRender() { + this.template = undefined; + this.isRendered = false; + this.connectedCallback(); + } + + /** + * Checks if the switch value is missing + * @returns {boolean} + */ + valueMissing() { + if (this.isRequired() && !this.checked) return true; + return false; + } + + /** + * Checks if the switch should be serialized when it is set inside a gameface form control element + * @returns {boolean} + */ + willSerialize() { + if (!this.checked || this.nameMissing()) return false; + return true; + } + + /** + * Sets up the switch based on the attributes it has and attaches the event listeners + */ + setup() { + if (this._isDefault) this._handle.classList.add('guic-switch-toggle-handle-default'); + if (this._isInset) this._switch.classList.add('guic-switch-toggle-inset'); + this.toggleClasses(this.checked); + this.toggleDisabled(this.disabled); + + this.attachEventListeners(); + } + + // eslint-disable-next-line require-jsdoc + attachEventListeners() { + this._container.addEventListener('mousedown', this.onClick); + } + + + isStatePropValid(name, value) { + const schemaProperty = this.stateSchema[name]; + + if (!schemaProperty) { + console.error(`A property ${name} does not exist on type ${this.tagName.toLowerCase()}!`); + return false; + } + + const type = typeof value; + if (schemaProperty.type.includes('array')) { + const isArray = Array.isArray(value); + if (isArray) return true; + } + + if (!schemaProperty.type.includes(type)) { + console.error(`Property ${name} can not be of type - ${type}. Allowed types are: ${schemaProperty.type.join(',')}`); + return false; + } + + return true; + } + /** + * Changes the styles of the switch and if it's checked + */ + onClick() { + this.checked = !this.checked; + } + + /** + * Changes the classes of the switch elements + * @param {boolean} checked + */ + toggleClasses(checked = false) { + this._handle.classList.toggle('guic-switch-toggle-handle-checked', checked); + this._switch.classList.toggle('guic-switch-toggle-checked', checked); + + if (this._isTextInside) { + this._textChecked.classList.toggle('guic-switch-text-hidden', checked ? false : true); + this._textUnchecked.classList.toggle('guic-switch-text-hidden', checked ? true : false); + } + } + + /** + * Toggles the disabled state of the switch. Can be used externaly to enable or disabled the switch + * @param {boolean} disabled + */ + toggleDisabled(disabled = false) { + this._container.classList.toggle('guic-switch-toggle-disabled', disabled); + } +} +customElements.define('gameface-switch', Switch); +export default Switch; diff --git a/components/tabs/index.html b/components/tabs/index.html index ce14c45fe..641a209b5 100644 --- a/components/tabs/index.html +++ b/components/tabs/index.html @@ -13,32 +13,33 @@ rel="stylesheet" href="./coherent-gameface-components-theme.css" > - + > --> - Chapter One - + Chapter One +
- Nested Chapter One - Nested Chapter One Content - Nested Chapter Two - Nested Chapter Two Content - Nested Chapter Three - Nested Chapter Three Content + Nested Chapter One +
Nested Chapter One Content
+ Nested Chapter Two +
Nested Chapter Two Content
+ Nested Chapter Three +
Nested Chapter Three Content
- - Chapter Two - Chapter Two Content - Chapter Three - Chapter Three Content - Chapter Four - Chapter Four Content +
+ Chapter Two +
Chapter Two Content
+ Chapter Three +
Chapter Three Content
+ Chapter Four +
Chapter Four Content
+ \ No newline at end of file diff --git a/components/tabs/script.js b/components/tabs/script.js index b0f819981..4074e8b32 100644 --- a/components/tabs/script.js +++ b/components/tabs/script.js @@ -3,20 +3,88 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import template from './template.html'; +// import { Components } from 'coherent-gameface-components'; +// const components = new Components(); +// import template from './template.html'; let tabsCounter = 0; let panelsCounter = 0; -const KEYCODES = components.KEYCODES; -const BaseComponent = components.BaseComponent; +// const KEYCODES = components.KEYCODES; +// const BaseComponent = components.BaseComponent; +const template = ` + +
+
+ + First Tab + Second Tab + +
+
+ +
First Tab Content
+
Second Tab Content
+
+
+
`; /** * Class definition of the gameface-tabs custom element */ -class Tabs extends BaseComponent { +class Tabs extends HTMLElement { /* eslint-disable require-jsdoc */ constructor() { super(); @@ -24,7 +92,7 @@ class Tabs extends BaseComponent { this.template = template; // bind the scope to this so that we can access the current instance - this.onKeyDown = this.onKeyDown.bind(this); + // this.onKeyDown = this.onKeyDown.bind(this); this.onClick = this.onClick.bind(this); this.url = '/components/tabs/template.html'; @@ -37,24 +105,50 @@ class Tabs extends BaseComponent { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - // render the component - components.renderOnce(this); - - this.tabSlot = this.querySelector('[data-name="tab"]'); - this.panelSlot = this.querySelector('[data-name="panel"]'); + // this.setupTemplate(data, () => { + // render the component + // components.renderOnce(this); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.tabSlot = this.shadowRoot.querySelector('slot[name="tab"]'); + this.panelSlot = this.shadowRoot.querySelector('slot[name="panel"]'); - this.attachEventListeners(); + this.attachEventListeners(); + this.tabs.forEach((tab, index) => { + tab.index = tabsCounter++; + tab.selected = false; + }); + this.panels.forEach((panel, index) => { + panel.index = panelsCounter++; + panel.selected = false; + panel.style.display = 'none'; }); + this.selectTab(this.tabs[0]); + // }); } - connectedCallback() { - this.tabs = this.getElementsByTagName('tab-heading'); - this.panels = this.getElementsByTagName('tab-panel'); + get tabs() { + return this.tabSlot.assignedElements(); + } - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + get panels() { + return this.panelSlot.assignedElements(); + } + + get selectedTab() { + return this.tabs.find(tab => tab.selected); + } + + get selectedPanel() { + return this.panels.find(panel => panel.selected); + } + + connectedCallback() { + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /* eslint-enable require-jsdoc */ @@ -73,7 +167,8 @@ class Tabs extends BaseComponent { * @returns {HTMLElement} - the panel. */ getPanelForTab(tab) { - return this.querySelector(`tab-panel[index="${tab.getAttribute('index')}"]`); + return this.panels.find(t => t.index === tab.index); + // return this.querySelector(`tab-panel[index="${tab.getAttribute('index')}"]`); } /** @@ -81,7 +176,8 @@ class Tabs extends BaseComponent { * @returns {Array} - the tabs of the tab component. */ getAllTabs() { - return Array.from(this.querySelector('.guic-tabs-header').querySelectorAll('tab-heading')); + return this.tabs; + // return Array.from(this.querySelector('.guic-tabs-header').querySelectorAll('tab-heading')); } /** @@ -89,16 +185,17 @@ class Tabs extends BaseComponent { * @returns {Array} - the panels of the tab component. */ getAllPanels() { - const panels = []; - let tabsPanel = this.querySelector(`.guic-tabs-panel`); - // If is used without filling the slots we need to get the children of the component-slot element - if (tabsPanel.children.length === 1 && tabsPanel.children[0].tagName === 'COMPONENT-SLOT') { - tabsPanel = tabsPanel.children[0]; - } - Array.from(tabsPanel.children).forEach((child) => { - if (child instanceof TabPanel) panels.push(child); - }); - return panels; + return this.panels; + // const panels = []; + // let tabsPanel = this.querySelector(`.guic-tabs-panel`); + // // If is used without filling the slots we need to get the children of the component-slot element + // if (tabsPanel.children.length === 1 && tabsPanel.children[0].tagName === 'COMPONENT-SLOT') { + // tabsPanel = tabsPanel.children[0]; + // } + // Array.from(tabsPanel.children).forEach((child) => { + // if (child instanceof TabPanel) panels.push(child); + // }); + // return panels; } /** @@ -106,11 +203,11 @@ class Tabs extends BaseComponent { * No tab is selected and no panel is visible. */ reset() { - const tabs = this.getAllTabs(); - const panels = this.getAllPanels(); + // const tabs = this.getAllTabs(); + // const panels = this.getAllPanels(); - tabs.forEach(tab => tab.selected = false); - panels.forEach(panel => panel.selected = false); + this.tabs.forEach(tab => tab.selected = false); + this.panels.forEach(panel => panel.selected = false); } /** @@ -118,11 +215,11 @@ class Tabs extends BaseComponent { * controls respectively. */ attachEventListeners() { - this.addEventListener('keydown', this.onKeyDown); + // this.addEventListener('keydown', this.onKeyDown); - const tabHeadings = this.getAllTabs(); + // const tabHeadings = this.getAllTabs(); - for (const tabHeading of tabHeadings) { + for (const tabHeading of this.tabs) { tabHeading.addEventListener('click', this.onClick); } } @@ -132,6 +229,12 @@ class Tabs extends BaseComponent { * @param {TabHeading} newTab - the tab which has been clicked on. */ selectTab(newTab) { + this.selectedTab?.classList.remove('guic-tabs-active-tab'); + const currentPanel = this.selectedPanel; + if (currentPanel) { + currentPanel.classList.remove('guic-tabs-active-panel'); + currentPanel.style.display = 'none'; + } // Deselect all tabs and hide all panels. this.reset(); // Get the panel that the `newTab` is associated with. @@ -143,6 +246,9 @@ class Tabs extends BaseComponent { } newTab.selected = true; newPanel.selected = true; + newTab.classList.add('guic-tabs-active-tab'); + newPanel.classList.add('guic-tabs-active-panel'); + newPanel.style.display = 'block'; // Show scrollbar inside the tabs panel because if the panel has been hidden then the scrollable container will be // hidden as well and that is why here we force it to recalculate if it should be visible or not. newPanel.querySelectorAll('gameface-scrollable-container').forEach(el => el.shouldShowScrollbar()); @@ -192,179 +298,179 @@ class Tabs extends BaseComponent { return tabs[tabs.length - 1]; } - /** - * Called on keydown. - * Gets the currently pressed key from the event and calls a function based - * on the key code. - * @param {KeyboardEvent} event - the event object - */ - onKeyDown(event) { - if (event.target.tagName.toLowerCase() !== 'tab-heading' || event.altKey) return; - - // The switch-case will determine which tab should be marked as active - // depending on the key that was pressed. - let newTab; - switch (event.keyCode) { - case KEYCODES.LEFT: - case KEYCODES.UP: - newTab = this.getPrevTab(); - break; - - case KEYCODES.RIGHT: - case KEYCODES.DOWN: - newTab = this.getNextTab(); - break; - - case KEYCODES.HOME: - newTab = this.getFirstTab(); - break; - - case KEYCODES.END: - newTab = this.getLastTab(); - break; - default: - return; - } - - event.preventDefault(); - this.selectTab(newTab); - } -} - -/** - * Class definition of the tab heading custom element - */ -class TabHeading extends HTMLElement { - /* eslint-disable require-jsdoc */ - static get observedAttributes() { - return ['selected']; - } - - attributeChangedCallback(name, oldValue, newValue) { - if (!this.isRendered) return; - - if (name === 'selected') this.updateSelectedState(newValue !== null); - } - - get selected() { - return this._selected; - } - - set selected(value) { - if (value) { - this.setAttribute('selected', ''); - } else { - this.removeAttribute('selected'); - } - } - - updateSelectedState(value) { - this._selected = value; - - if (value) { - this.classList.add('guic-tabs-active-tab'); - } else { - this.classList.remove('guic-tabs-active-tab'); - } - - this.setAttribute('tabindex', value ? '0' : '-1'); - } - - get index() { - return this._index; - } - - set index(value) { - this._index = value; - this.setAttribute('index', value); - } - - constructor() { - super(); - - this._selected = false; - } - - connectedCallback() { - if (!this.index) { - this.index = `${tabsCounter++}`; - } - - this.updateSelectedState(this.hasAttribute('selected')); - this.isRendered = true; - } - /* eslint-enable require-jsdoc */ -} - -/** - * Class definition of the tab panel custom element - */ -class TabPanel extends HTMLElement { - /* eslint-disable require-jsdoc */ - - static get observedAttributes() { - return ['selected']; - } - - get selected() { - return this._selected; - } - - set selected(value) { - if (value) { - this.setAttribute('selected', ''); - } else { - this.removeAttribute('selected'); - } - } - - updateSelectedState(value) { - this._selected = value; - - if (value) { - this.classList.add('guic-tabs-active-panel'); - } else { - this.classList.remove('guic-tabs-active-panel'); - } - - this.style.display = value ? 'block' : 'none'; - } - - get index() { - return this._index; - } - - set index(value) { - this._index = value; - this.setAttribute('index', value); - } - - constructor() { - super(); - - this._selected = false; - } - - attributeChangedCallback(name, oldValue, newValue) { - if (!this.isRendered) return; - - if (name === 'selected') this.updateSelectedState(newValue !== null); - } - - connectedCallback() { - if (!this.index) { - this.index = `${panelsCounter++}`; - } - - this.updateSelectedState(this.hasAttribute('selected')); - this.isRendered = true; - } - /* eslint-enable require-jsdoc */ + // /** + // * Called on keydown. + // * Gets the currently pressed key from the event and calls a function based + // * on the key code. + // * @param {KeyboardEvent} event - the event object + // */ + // onKeyDown(event) { + // if (event.target.tagName.toLowerCase() !== 'tab-heading' || event.altKey) return; + + // // The switch-case will determine which tab should be marked as active + // // depending on the key that was pressed. + // let newTab; + // switch (event.keyCode) { + // case KEYCODES.LEFT: + // case KEYCODES.UP: + // newTab = this.getPrevTab(); + // break; + + // case KEYCODES.RIGHT: + // case KEYCODES.DOWN: + // newTab = this.getNextTab(); + // break; + + // case KEYCODES.HOME: + // newTab = this.getFirstTab(); + // break; + + // case KEYCODES.END: + // newTab = this.getLastTab(); + // break; + // default: + // return; + // } + + // event.preventDefault(); + // this.selectTab(newTab); + // } } -components.defineCustomElement('gameface-tabs', Tabs); -components.defineCustomElement('tab-heading', TabHeading); -components.defineCustomElement('tab-panel', TabPanel); +// /** +// * Class definition of the tab heading custom element +// */ +// class TabHeading extends HTMLElement { +// /* eslint-disable require-jsdoc */ +// static get observedAttributes() { +// return ['selected']; +// } + +// attributeChangedCallback(name, oldValue, newValue) { +// if (!this.isRendered) return; + +// if (name === 'selected') this.updateSelectedState(newValue !== null); +// } + +// get selected() { +// return this._selected; +// } + +// set selected(value) { +// if (value) { +// this.setAttribute('selected', ''); +// } else { +// this.removeAttribute('selected'); +// } +// } + +// updateSelectedState(value) { +// this._selected = value; + +// if (value) { +// this.classList.add('guic-tabs-active-tab'); +// } else { +// this.classList.remove('guic-tabs-active-tab'); +// } + +// this.setAttribute('tabindex', value ? '0' : '-1'); +// } + +// get index() { +// return this._index; +// } + +// set index(value) { +// this._index = value; +// this.setAttribute('index', value); +// } + +// constructor() { +// super(); + +// this._selected = false; +// } + +// connectedCallback() { +// if (!this.index) { +// this.index = `${tabsCounter++}`; +// } + +// this.updateSelectedState(this.hasAttribute('selected')); +// this.isRendered = true; +// } +// /* eslint-enable require-jsdoc */ +// } + +// /** +// * Class definition of the tab panel custom element +// */ +// class TabPanel extends HTMLElement { +// /* eslint-disable require-jsdoc */ + +// static get observedAttributes() { +// return ['selected']; +// } + +// get selected() { +// return this._selected; +// } + +// set selected(value) { +// if (value) { +// this.setAttribute('selected', ''); +// } else { +// this.removeAttribute('selected'); +// } +// } + +// updateSelectedState(value) { +// this._selected = value; + +// if (value) { +// this.classList.add('guic-tabs-active-panel'); +// } else { +// this.classList.remove('guic-tabs-active-panel'); +// } + +// this.style.display = value ? 'block' : 'none'; +// } + +// get index() { +// return this._index; +// } + +// set index(value) { +// this._index = value; +// this.setAttribute('index', value); +// } + +// constructor() { +// super(); + +// this._selected = false; +// } + +// attributeChangedCallback(name, oldValue, newValue) { +// if (!this.isRendered) return; + +// if (name === 'selected') this.updateSelectedState(newValue !== null); +// } + +// connectedCallback() { +// if (!this.index) { +// this.index = `${panelsCounter++}`; +// } + +// this.updateSelectedState(this.hasAttribute('selected')); +// this.isRendered = true; +// } +// /* eslint-enable require-jsdoc */ +// } + +customElements.define('gameface-tabs', Tabs); +// components.defineCustomElement('tab-heading', TabHeading); +// components.defineCustomElement('tab-panel', TabPanel); -export { Tabs, TabHeading, TabPanel }; +// export { Tabs, TabHeading, TabPanel }; diff --git a/components/text-field/index.html b/components/text-field/index.html index 3ccc55909..824bc3652 100644 --- a/components/text-field/index.html +++ b/components/text-field/index.html @@ -3,7 +3,7 @@ - + +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+`; const supportedTextFieldTypes = { TEXT: 'text', PASSWORD: 'password', @@ -430,16 +617,20 @@ class TextField extends CustomElementValidator { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - this.initTextField(); - }); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.initTextField(); + // }); } connectedCallback() { - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } /* eslint-enable require-jsdoc */ @@ -732,14 +923,14 @@ class TextField extends CustomElementValidator { * Cache the component elements */ initTextFieldElements() { - this.componentContainer = this.querySelector('.guic-text-field-container'); - this.inputElement = this.querySelector('.guic-text-field'); - this.labelElement = this.querySelector('.guic-text-field-label'); - this.searchRemoveElement = this.querySelector('.guic-search-remove'); - this.numberControlElement = this.querySelector('.guic-number-control'); - this.placeholderElement = this.querySelector('.guic-text-field-placeholder'); - this.increaseInputValueElement = this.querySelector('.guic-number-increase'); - this.decreaseInputValueElement = this.querySelector('.guic-number-decrease'); + this.componentContainer = this.shadowRoot.querySelector('.guic-text-field-container'); + this.inputElement = this.shadowRoot.querySelector('.guic-text-field'); + this.labelElement = this.shadowRoot.querySelector('.guic-text-field-label'); + this.searchRemoveElement = this.shadowRoot.querySelector('.guic-search-remove'); + this.numberControlElement = this.shadowRoot.querySelector('.guic-number-control'); + this.placeholderElement = this.shadowRoot.querySelector('.guic-text-field-placeholder'); + this.increaseInputValueElement = this.shadowRoot.querySelector('.guic-number-increase'); + this.decreaseInputValueElement = this.shadowRoot.querySelector('.guic-number-decrease'); } /** @@ -756,5 +947,5 @@ class TextField extends CustomElementValidator { } } } -components.defineCustomElement('gameface-text-field', TextField); -export default TextField; +customElements.define('gameface-text-field', TextField); +// export default TextField; diff --git a/components/toast/index.html b/components/toast/index.html index c24977832..3aba2cd78 100644 --- a/components/toast/index.html +++ b/components/toast/index.html @@ -67,7 +67,7 @@ .heart-toast-close { width: 100%; height: 100%; - background-image: url(imgs/like.png); + background-image: url(./demo/imgs/like.png); animation: beat 1s linear infinite alternate; } @@ -162,7 +162,7 @@

Toast component

>
Hidden toast found!
- + + \ No newline at end of file diff --git a/components/tooltip/script.js b/components/tooltip/script.js index 8bc6bbb23..951a4ddf3 100644 --- a/components/tooltip/script.js +++ b/components/tooltip/script.js @@ -3,18 +3,47 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Components } from 'coherent-gameface-components'; -const components = new Components(); -import template from './template.html'; +// import { Components } from 'coherent-gameface-components'; +// const components = new Components(); +// import template from './template.html'; const TOOLTIP_MARGIN = 5; const TOOLTIP_POSITIONS = ['top', 'bottom', 'left', 'right']; const NOT_A_PROMISE_ERROR = 'The value in async mode must be a function that returns a promise.'; -const BaseComponent = components.BaseComponent; +// const BaseComponent = components.BaseComponent; +const template = ` + +
+ +
+`; /** * Class definition of the gameface tooltip custom element */ -class Tooltip extends BaseComponent { +class Tooltip extends HTMLElement { /* eslint-disable require-jsdoc */ constructor() { super(); @@ -68,11 +97,11 @@ class Tooltip extends BaseComponent { * @param {object} data */ init(data) { - this.setupTemplate(data, () => { - components.renderOnce(this); - this.attachEventListeners(); - this._messageSlot = this.querySelector('.guic-tooltip').firstElementChild; - }); + // this.setupTemplate(data, () => { + // components.renderOnce(this); + this.attachEventListeners(); + this._messageSlot = this.shadowRoot.querySelector('slot[name="message"]').assignedNodes()[0]; + // }); } connectedCallback() { @@ -88,10 +117,13 @@ class Tooltip extends BaseComponent { this.handleDocumentClick = this.handleDocumentClick.bind(this); this.resizeDebounced = this.debounce(this.onWindowResize); - - components.loadResource(this) - .then(this.init) - .catch(err => console.error(err)); + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = this.template; + this.isRendered = true; + this.init(); + // components.loadResource(this) + // .then(this.init) + // .catch(err => console.error(err)); } onWindowResize() { @@ -337,6 +369,6 @@ class Tooltip extends BaseComponent { } } -components.defineCustomElement('gameface-tooltip', Tooltip); +customElements.define('gameface-tooltip', Tooltip); -export default Tooltip; +// export default Tooltip; diff --git a/lib/components.js b/lib/components.js index 8dc67e919..16b815e28 100644 --- a/lib/components.js +++ b/lib/components.js @@ -30,20 +30,7 @@ class BaseComponent extends HTMLElement { get instanceType() { return 'BaseComponent'; } - /** - * Called when the template of a component was loaded. - * @param {object} data - * @param {function} callback - * @returns {undefined} - */ - setupTemplate(data, callback) { - if (!this.isConnected) { - return console.log(`DEBUG: component ${this.tagName} was not initialized because it was disconnected from the DOM!`); - } - this.template = data.template; - callback(data.template); - } /** * Validate if a value can be set on the state. * @param {string} name - the name of the property. @@ -410,7 +397,7 @@ class TextFieldValidator { } // eslint-disable-next-line max-lines-per-function, require-jsdoc -const Components = function () { +const main = function () { const GF_COMPONENT_SLOT_TAG_NAME = 'component-slot'; const KEYCODES = { DOWN: 40, @@ -862,5 +849,5 @@ const Components = function () { return components; }; - -export { Components }; +const components = main(); +export { components };