diff --git a/package-lock.json b/package-lock.json
index 81f98f6..cf665ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,11 @@
"name": "ha-combined-card",
"version": "1.0.4",
"license": "MIT",
+ "dependencies": {
+ "query-selector-shadow-dom": "^1.0.1"
+ },
"devDependencies": {
+ "@types/query-selector-shadow-dom": "^1.0.4",
"custom-card-helpers": "^1.9.0",
"esbuild": "^0.20.1",
"lit": "^3.1.2"
@@ -456,6 +460,13 @@
"@lit-labs/ssr-dom-shim": "^1.2.0"
}
},
+ "node_modules/@types/query-selector-shadow-dom": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@types/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.4.tgz",
+ "integrity": "sha512-8jfGPD0wCMCdyBvrvOrWVn8bHL1UEjkPVJKsqNZpEXp+a7mIIvvGpJMd6n6dlNl7IkG2ryxIVqFI516RPE0uhQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
@@ -627,6 +638,12 @@
"@types/trusted-types": "^2.0.2"
}
},
+ "node_modules/query-selector-shadow-dom": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz",
+ "integrity": "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==",
+ "license": "MIT"
+ },
"node_modules/rollup": {
"version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
diff --git a/package.json b/package.json
index 4499264..86965cd 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,11 @@
"keywords": [],
"author": "",
"license": "MIT",
+ "dependencies": {
+ "query-selector-shadow-dom": "^1.0.1"
+ },
"devDependencies": {
+ "@types/query-selector-shadow-dom": "^1.0.4",
"custom-card-helpers": "^1.9.0",
"esbuild": "^0.20.1",
"lit": "^3.1.2"
diff --git a/src/combined-card-editor.ts b/src/combined-card-editor.ts
index ee2d50c..9529f88 100644
--- a/src/combined-card-editor.ts
+++ b/src/combined-card-editor.ts
@@ -1,88 +1,91 @@
import { html, LitElement } from "lit";
import { HomeAssistant, LovelaceCardConfig, LovelaceCardEditor, LovelaceConfig } from 'custom-card-helpers';
-import { NAME, EDITOR_NAME, LOG_EDITOR as LOG } from './utils';
-
-class CombinedCardEditor extends LitElement implements LovelaceCardEditor {
- private _hass?: HomeAssistant;
- private _lovelace?: LovelaceConfig;
- private _stackCardEditor?;
- private _config = {};
-
- private _setEditorConfig(config: LovelaceCardConfig) {
- // @ts-ignore
- if (this._stackCardEditor) {
- this._stackCardEditor.setConfig({
- type: 'vertical-stack',
- cards: config.cards || []
- });
+import { LOG_EDITOR as LOG } from './utils';
+
+export const editorFactory = (NAME: string) => {
+ class CombinedCardEditor extends LitElement implements LovelaceCardEditor {
+ private _hass?: HomeAssistant;
+ private _lovelace?: LovelaceConfig;
+ private _stackCardEditor?;
+ private _config = {};
+
+ private _setEditorConfig(config: LovelaceCardConfig) {
+ // @ts-ignore
+ if (this._stackCardEditor) {
+ this._stackCardEditor.setConfig({
+ type: 'vertical-stack',
+ cards: config.cards || []
+ });
+ }
}
- }
- setConfig(config: LovelaceCardConfig): void {
- this._config = {
- // I think this won't allow removing the hidden values
- // ...this._config,
- ...config
- };
+ setConfig(config: LovelaceCardConfig): void {
+ this._config = {
+ // I think this won't allow removing the hidden values
+ // ...this._config,
+ ...config
+ };
- this._setEditorConfig(this._config as LovelaceCardConfig);
- }
+ this._setEditorConfig(this._config as LovelaceCardConfig);
+ }
- configChanged(newConfig: LovelaceCardConfig): void {
- const event = new Event('config-changed', {
- bubbles: true,
- composed: true
- });
+ configChanged(newConfig: LovelaceCardConfig): void {
+ const event = new Event('config-changed', {
+ bubbles: true,
+ composed: true
+ });
- // @ts-ignore
- event.detail = { config: newConfig };
+ // @ts-ignore
+ event.detail = { config: newConfig };
- this.dispatchEvent(event);
- }
+ this.dispatchEvent(event);
+ }
- protected render() {
- LOG('render', this._stackCardEditor);
+ protected render() {
+ LOG('render', this._stackCardEditor);
- if (this._hass) {
- this._stackCardEditor.hass = this._hass;
- }
+ if (this._hass) {
+ this._stackCardEditor.hass = this._hass;
+ }
- if (this._lovelace) {
- this._stackCardEditor.lovelace = this._lovelace;
- }
+ if (this._lovelace) {
+ this._stackCardEditor.lovelace = this._lovelace;
+ }
- this._stackCardEditor.addEventListener('config-changed', ev => {
- ev.stopPropagation();
+ this._stackCardEditor.addEventListener('config-changed', ev => {
+ ev.stopPropagation();
- this.configChanged({
- ...this._config,
- ...ev.detail.config,
- type: `custom:${NAME}`
+ this.configChanged({
+ ...this._config,
+ ...ev.detail.config,
+ type: `custom:${NAME}`
+ });
});
- });
- return html`
${this._stackCardEditor}
`;
- }
+ return html`${this._stackCardEditor}
`;
+ }
- set hass(hass: HomeAssistant) {
- this._hass = hass;
+ set hass(hass: HomeAssistant) {
+ this._hass = hass;
- if (this._stackCardEditor) {
- this._stackCardEditor.hass = hass;
+ if (this._stackCardEditor) {
+ this._stackCardEditor.hass = hass;
+ }
}
- }
- set lovelace(ll: LovelaceConfig) {
- this._lovelace = ll;
+ set lovelace(ll: LovelaceConfig) {
+ this._lovelace = ll;
- if (this._stackCardEditor) {
- this._stackCardEditor.lovelace = ll;
+ if (this._stackCardEditor) {
+ this._stackCardEditor.lovelace = ll;
+ }
}
- }
- set cardEditor(editor) {
- this._stackCardEditor = editor;
+ set cardEditor(editor) {
+ this._stackCardEditor = editor;
+ }
}
-}
-customElements.define(EDITOR_NAME, CombinedCardEditor);
+ return CombinedCardEditor;
+};
+
diff --git a/src/combined-card.ts b/src/combined-card.ts
index 2b403e3..66b38ee 100644
--- a/src/combined-card.ts
+++ b/src/combined-card.ts
@@ -1,7 +1,18 @@
-import { css, CSSResultGroup, html, LitElement } from "lit";
-import { state } from "lit/decorators.js";
+import { css, CSSResultGroup, html, LitElement } from 'lit';
+import { state } from 'lit/decorators.js';
import { HomeAssistant, LovelaceCardConfig, LovelaceCard } from 'custom-card-helpers';
-import { NAME, EDITOR_NAME, HELPERS, LOG, loadStackEditor, sleep } from './utils';
+import { HELPERS, LOG, loadStackEditor, sleep } from './utils';
+
+import { editorFactory } from "./combined-card-editor";
+
+const NAME = 'combined-card';
+const EDITOR_NAME = `${NAME}-editor`;
+
+export const card = {
+ type: NAME,
+ name: "Catdad: Combined Card",
+ description: "Combine a stack of cards into a single seamless card",
+};
const getRandomId = (): string => Math.random().toString(36).slice(2);
@@ -229,3 +240,4 @@ class CombinedCard extends LitElement implements LovelaceCard {
}
customElements.define(NAME, CombinedCard);
+customElements.define(EDITOR_NAME, editorFactory(NAME));
diff --git a/src/kiosk-card.ts b/src/kiosk-card.ts
new file mode 100644
index 0000000..9a0f538
--- /dev/null
+++ b/src/kiosk-card.ts
@@ -0,0 +1,147 @@
+import { css, CSSResultGroup, html, LitElement } from "lit";
+import { state } from "lit/decorators.js";
+import { querySelectorDeep } from "query-selector-shadow-dom";
+import { HomeAssistant, LovelaceCardConfig, LovelaceCard } from 'custom-card-helpers';
+import { LOG } from './utils';
+
+const NAME = 'kiosk-card';
+const EDITOR_NAME = `${NAME}-editor`;
+
+export const card = {
+ type: NAME,
+ name: 'Catdad: Kiosk Card',
+ description: 'Hide the navigation UI for the dashboard where this card is rendered'
+};
+
+class KioskCard extends LitElement implements LovelaceCard {
+ @state() private _config?: LovelaceCardConfig;
+ @state() private _editMode: boolean = false;
+
+ private _hass?: HomeAssistant;
+
+ set hass(hass: HomeAssistant) {
+ this._hass = hass;
+ }
+
+ set editMode(editMode: boolean) {
+ this._editMode = editMode;
+
+ if (editMode) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+ }
+
+ public async getCardSize(): Promise {
+ return 4;
+ }
+
+ public setConfig(config: LovelaceCardConfig): void {
+ this._config = Object.assign({}, KioskCard.getStubConfig(), config);
+ }
+
+ private enable(): void {
+ try {
+ const header = querySelectorDeep('ha-panel-lovelace .header');
+ const view = querySelectorDeep('ha-panel-lovelace hui-view-container');
+ const thisCard = querySelectorDeep('.catdad-kiosk-card');
+
+ // LOG('kiosk mode got elements:', { header, view, thisCard });
+
+ // when this card is not being rendered, it should not apply kiosk mode
+ if (!thisCard) {
+ return;
+ }
+
+ if (!header || !view) {
+ throw new Error('could not find necessary elements to apply kiosk mode');
+ }
+
+ if (this._editMode) {
+ header.style.removeProperty('display');
+ view.style.removeProperty('padding-top');
+ } else {
+ header.style.display = 'none';
+ view.style.paddingTop = '0px';
+ }
+ } catch (e) {
+ LOG('failed to connect kiosk mode', e);
+ }
+ }
+
+ private disable(): void {
+ try {
+ const header = querySelectorDeep('ha-panel-lovelace .header');
+ const view = querySelectorDeep('ha-panel-lovelace hui-view-container');
+
+ // LOG('kiosk mode got elements:', { header, view });
+
+ if (!header || !view) {
+ throw new Error('could not find necessary elements to disconnect kiosk mode');
+ }
+
+ header.style.removeProperty('display');
+ view.style.removeProperty('padding-top');
+ } catch (e) {
+ LOG('failed to disconnect kiosk mode', e);
+ }
+ }
+
+ connectedCallback(): void {
+ super.connectedCallback()
+ // LOG('Kiosk card connected', this._editMode);
+ this.enable();
+ }
+
+ disconnectedCallback(): void {
+ super.disconnectedCallback();
+ // LOG('Kiosk card disconnected');
+ this.disable();
+ }
+
+ protected render() {
+ const styles = [
+ 'padding: var(--spacing, 12px)',
+ 'display: flex',
+ 'align-items: center',
+ 'justify-content: center',
+ ];
+
+ return html`
+
+ Kiosk mode card
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-card {
+ overflow: hidden;
+ }
+ `;
+ }
+
+ public static getConfigElement() {
+ return document.createElement(EDITOR_NAME);
+ }
+
+ static getStubConfig() {
+ return {
+ type: `custom:${NAME}`,
+ };
+ }
+}
+
+class KioskCardEditor extends LitElement {
+ setConfig() {}
+ configChanged() {}
+
+ render() {
+ return html`This card has no options!
`;
+ }
+}
+
+customElements.define(NAME, KioskCard);
+customElements.define(EDITOR_NAME, KioskCardEditor);
diff --git a/src/main.ts b/src/main.ts
index 237afa1..f4b6270 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,12 +1,6 @@
-import { NAME } from './utils';
-
-import "./combined-card";
-import "./combined-card-editor";
+import { card as combinedCard } from "./combined-card";
+import { card as kioskCard } from "./kiosk-card";
// Note: this is what adds the card to the UI card selector
(window as any).customCards = (window as any).customCards || [];
-(window as any).customCards.push({
- type: NAME,
- name: "Combined Card",
- description: "Combine a stack of cards into a single seamless card",
-});
+(window as any).customCards.push(combinedCard, kioskCard);