diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 98c934b..ae0e234 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,32 +1,23 @@ -// See https://aka.ms/vscode-remote/devcontainer.json for format details. +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/alpine { - "name": "Boilerplate Card Development", - "image": "ludeeus/container:monster", - "context": "..", - "appPort": ["5000:5000", "9123:8123"], - "postCreateCommand": "npm install", - "runArgs": [ - "-v", - "${env:HOME}${env:USERPROFILE}/.ssh:/tmp/.ssh" // This is added so you can push from inside the container - ], - "extensions": [ - "github.vscode-pull-request-github", - "eamodio.gitlens", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "bierner.lit-html", - "runem.lit-plugin", - "auchenberg.vscode-browser-preview", - "davidanson.vscode-markdownlint", - "redhat.vscode-yaml" - ], - "settings": { - "files.eol": "\n", - "editor.tabSize": 4, - "terminal.integrated.shell.linux": "/bin/bash", - "editor.formatOnPaste": false, - "editor.formatOnSave": true, - "editor.formatOnType": true, - "files.trimTrailingWhitespace": true - } + "name": "Alpine", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/vscode/devcontainers/typescript-node", + + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [ 5000 ], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "yarn" + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" } diff --git a/elements/formfield.js b/elements/formfield.js deleted file mode 100644 index 36479ce..0000000 --- a/elements/formfield.js +++ /dev/null @@ -1,10 +0,0 @@ -import { FormfieldBase } from '@material/mwc-formfield/mwc-formfield-base.js'; -import { styles as formfieldStyles } from '@material/mwc-formfield/mwc-formfield.css.js'; - -export const formfieldDefinition = { - 'mwc-formfield': class extends FormfieldBase { - static get styles() { - return formfieldStyles; - } - }, -}; diff --git a/elements/ignore/select.js b/elements/ignore/select.js deleted file mode 100644 index b1e1d15..0000000 --- a/elements/ignore/select.js +++ /dev/null @@ -1,8 +0,0 @@ -export const ignoreSelectFiles = [ - '@material/mwc-ripple/mwc-ripple.js', - '@material/mwc-menu/mwc-menu.js', - '@material/mwc-menu/mwc-menu-surface.js', - '@material/mwc-list/mwc-list.js', - '@material/mwc-list/mwc-list-item.js', - '@material/mwc-icon/mwc-icon.js', -]; diff --git a/elements/ignore/switch.js b/elements/ignore/switch.js deleted file mode 100644 index e13a8a7..0000000 --- a/elements/ignore/switch.js +++ /dev/null @@ -1 +0,0 @@ -export const ignoreSwitchFiles = ['@material/mwc-ripple/mwc-ripple.js']; diff --git a/elements/ignore/textfield.js b/elements/ignore/textfield.js deleted file mode 100644 index 987fd50..0000000 --- a/elements/ignore/textfield.js +++ /dev/null @@ -1 +0,0 @@ -export const ignoreTextfieldFiles = ['@material/mwc-notched-outline/mwc-notched-outline.js']; diff --git a/elements/select.js b/elements/select.js deleted file mode 100644 index 3a8a055..0000000 --- a/elements/select.js +++ /dev/null @@ -1,53 +0,0 @@ -import { SelectBase } from '@material/mwc-select/mwc-select-base.js'; -import { ListBase } from '@material/mwc-list/mwc-list-base.js'; -import { ListItemBase } from '@material/mwc-list/mwc-list-item-base.js'; -import { MenuBase } from '@material/mwc-menu/mwc-menu-base.js'; -import { MenuSurfaceBase } from '@material/mwc-menu/mwc-menu-surface-base.js'; -import { RippleBase } from '@material/mwc-ripple/mwc-ripple-base.js'; -import { NotchedOutlineBase } from '@material/mwc-notched-outline/mwc-notched-outline-base.js'; - -import { styles as selectStyles } from '@material/mwc-select/mwc-select.css'; -import { styles as listStyles } from '@material/mwc-list/mwc-list.css'; -import { styles as listItemStyles } from '@material/mwc-list//mwc-list-item.css'; -import { styles as rippleStyles } from '@material/mwc-ripple/mwc-ripple.css'; -import { styles as menuStyles } from '@material/mwc-menu/mwc-menu.css'; -import { styles as menuSurfaceStyles } from '@material/mwc-menu/mwc-menu-surface.css'; -import { styles as notchedOutlineStyles } from '@material/mwc-notched-outline/mwc-notched-outline.css'; - -export const selectDefinition = { - 'mwc-select': class extends SelectBase { - static get styles() { - return selectStyles; - } - }, - 'mwc-list': class extends ListBase { - static get styles() { - return listStyles; - } - }, - 'mwc-list-item': class extends ListItemBase { - static get styles() { - return listItemStyles; - } - }, - 'mwc-ripple': class extends RippleBase { - static get styles() { - return rippleStyles; - } - }, - 'mwc-menu': class extends MenuBase { - static get styles() { - return menuStyles; - } - }, - 'mwc-menu-surface': class extends MenuSurfaceBase { - static get styles() { - return menuSurfaceStyles; - } - }, - 'mwc-notched-outline': class extends NotchedOutlineBase { - static get styles() { - return notchedOutlineStyles; - } - }, -}; diff --git a/elements/switch.js b/elements/switch.js deleted file mode 100644 index 023589d..0000000 --- a/elements/switch.js +++ /dev/null @@ -1,17 +0,0 @@ -import { SwitchBase } from '@material/mwc-switch/deprecated/mwc-switch-base.js'; -import { RippleBase } from '@material/mwc-ripple/mwc-ripple-base.js'; -import { styles as switchStyles } from '@material/mwc-switch/deprecated/mwc-switch.css'; -import { styles as rippleStyles } from '@material/mwc-ripple/mwc-ripple.css'; - -export const switchDefinition = { - 'mwc-switch': class extends SwitchBase { - static get styles() { - return switchStyles; - } - }, - 'mwc-ripple': class extends RippleBase { - static get styles() { - return rippleStyles; - } - }, -}; diff --git a/elements/textfield.js b/elements/textfield.js deleted file mode 100644 index c644020..0000000 --- a/elements/textfield.js +++ /dev/null @@ -1,18 +0,0 @@ -import { TextFieldBase } from '@material/mwc-textfield/mwc-textfield-base.js'; -import { NotchedOutlineBase } from '@material/mwc-notched-outline/mwc-notched-outline-base.js'; - -import { styles as textfieldStyles } from '@material/mwc-textfield/mwc-textfield.css'; -import { styles as notchedOutlineStyles } from '@material/mwc-notched-outline/mwc-notched-outline.css'; - -export const textfieldDefinition = { - 'mwc-textfield': class extends TextFieldBase { - static get styles() { - return textfieldStyles; - } - }, - 'mwc-notched-outline': class extends NotchedOutlineBase { - static get styles() { - return notchedOutlineStyles; - } - }, -}; diff --git a/package.json b/package.json index 2273e4f..dd335fe 100644 --- a/package.json +++ b/package.json @@ -15,51 +15,41 @@ "author": "Ian Richardson ", "license": "MIT", "dependencies": { - "@lit-labs/scoped-registry-mixin": "^1.0.0", - "@material/mwc-formfield": "^0.25.3", - "@material/mwc-list": "^0.25.3", - "@material/mwc-menu": "^0.25.3", - "@material/mwc-notched-outline": "^0.25.3", - "@material/mwc-ripple": "^0.25.3", - "@material/mwc-select": "^0.25.3", - "@material/mwc-switch": "^0.25.3", - "@material/mwc-textfield": "^0.25.3", - "custom-card-helpers": "^1.7.2", - "home-assistant-js-websocket": "^5.11.1", - "lit": "^2.0.0" + "custom-card-helpers": "^1.9.0", + "home-assistant-js-websocket": "^9.3.0", + "lit": "^2.8.0", + "@lit-labs/context": "0.4.1", + "@lit-labs/motion": "1.0.7", + "@lit-labs/observers": "2.0.2", + "@lit-labs/virtualizer": "2.0.12" }, "devDependencies": { "@babel/core": "^7.15.0", - "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-decorators": "^7.14.5", - "@rollup/plugin-json": "^4.1.0", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "eslint": "^7.32.0", - "eslint-config-airbnb-base": "^14.2.1", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-import": "^2.24.0", - "eslint-plugin-prettier": "^4.0.0", - "prettier": "^2.4.1", - "rollup": "^2.58.0", - "rollup-plugin-babel": "^4.4.0", - "rollup-plugin-commonjs": "^10.1.0", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-serve": "^1.1.0", - "rollup-plugin-terser": "^7.0.2", - "rollup-plugin-typescript2": "^0.30.0", - "typescript": "^4.4.3" - }, - "resolutions": { - "lit": "^2.1.2", - "lit-html": "2.1.2", - "lit-element": "3.1.2", - "@lit/reactive-element": "1.2.1" + "@babel/plugin-proposal-decorators": "^7.24.6", + "@eslint/js": "^9.4.0", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^25.0.8", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/eslint__js": "^8.42.3", + "eslint": "^8.57.0", + "rollup": "^4.18.0", + "rollup-plugin-serve": "^1.1.1", + "rollup-plugin-sizes": "^1.0.6", + "typescript": "^5.4.5", + "typescript-eslint": "^7.11.0" }, "scripts": { - "start": "rollup -c rollup.config.dev.js --watch", + "start": "rollup -c rollup.config.dev.mjs --watch", "build": "npm run lint && npm run rollup", "lint": "eslint src/*.ts", - "rollup": "rollup -c" - } -} + "rollup": "rollup -c --logLevel=debug -m" + }, + "resolutions": { + "lit": "2.8.0", + "@lit/reactive-element": "1.6.3" + }, + "packageManager": "yarn@4.2.2" +} \ No newline at end of file diff --git a/rollup-plugins/ignore.js b/rollup-plugins/ignore.js deleted file mode 100644 index 029995c..0000000 --- a/rollup-plugins/ignore.js +++ /dev/null @@ -1,24 +0,0 @@ -export default function (userOptions = {}) { - // Files need to be absolute paths. - // This only works if the file has no exports - // and only is imported for its side effects - const files = userOptions.files || []; - - if (files.length === 0) { - return { - name: 'ignore', - }; - } - - return { - name: 'ignore', - - load(id) { - return files.some((toIgnorePath) => id.startsWith(toIgnorePath)) - ? { - code: '', - } - : null; - }, - }; -} diff --git a/rollup.config.dev.mjs b/rollup.config.dev.mjs new file mode 100644 index 0000000..d39c124 --- /dev/null +++ b/rollup.config.dev.mjs @@ -0,0 +1,39 @@ +import resolve from '@rollup/plugin-node-resolve'; +import typescript from '@rollup/plugin-typescript'; +import babel from '@rollup/plugin-babel'; +import serve from 'rollup-plugin-serve'; +import terser from '@rollup/plugin-terser'; +import json from '@rollup/plugin-json'; +import sizes from 'rollup-plugin-sizes'; + +export default { + input: ['src/boilerplate-card.ts'], + output: { + dir: './dist', + format: 'es', + }, + logLevel: 'debug', + plugins: [ + resolve(), + typescript(), + json(), + babel({ + exclude: 'node_modules/**', + format: 'es', + include: 'src/**', + exclude: 'homeassistant-frontend/**', + babelHelpers: 'bundled', + }), + terser(), + serve({ + contentBase: './dist', + host: '0.0.0.0', + port: 5000, + allowCrossOrigin: true, + headers: { + 'Access-Control-Allow-Origin': '*', + }, + }), + sizes({ details: true }), + ], +}; diff --git a/rollup.config.mjs b/rollup.config.mjs new file mode 100644 index 0000000..1c63bc3 --- /dev/null +++ b/rollup.config.mjs @@ -0,0 +1,43 @@ +import typescript from '@rollup/plugin-typescript'; +import commonjs from '@rollup/plugin-commonjs'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import babel from '@rollup/plugin-babel'; +import terser from '@rollup/plugin-terser'; +import serve from 'rollup-plugin-serve'; +import json from '@rollup/plugin-json'; + +const dev = process.env.ROLLUP_WATCH; + +const serveopts = { + contentBase: ['./dist'], + host: '0.0.0.0', + port: 5000, + allowCrossOrigin: true, + headers: { + 'Access-Control-Allow-Origin': '*', + }, +}; + +const plugins = [ + nodeResolve({}), + commonjs(), + typescript(), + json(), + babel({ + exclude: 'node_modules/**', + babelHelpers: 'bundled', + }), + dev && serve(serveopts), + !dev && terser(), +]; + +export default [ + { + input: 'src/boilerplate-card.ts', + output: { + dir: 'dist', + format: 'es', + }, + plugins: [...plugins], + }, +]; diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index 54550c4..4cb1e8e 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -1,16 +1,12 @@ import { noChange } from 'lit'; -import { AttributePart, directive, Directive, DirectiveParameters } from 'lit/directive'; +import { AttributePart, directive, Directive, DirectiveParameters } from 'lit/directive.js'; import { ActionHandlerDetail, ActionHandlerOptions } from 'custom-card-helpers/dist/types'; import { fireEvent } from 'custom-card-helpers'; const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.maxTouchPoints > 0; -interface ActionHandler extends HTMLElement { - holdTime: number; - bind(element: Element, options): void; -} -interface ActionHandlerElement extends HTMLElement { +class ActionHandlerElement extends HTMLElement { actionHandler?: boolean; } @@ -20,7 +16,7 @@ declare global { } } -class ActionHandler extends HTMLElement implements ActionHandler { +class ActionHandler extends HTMLElement { public holdTime = 500; // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/boilerplate-card.ts b/src/boilerplate-card.ts index 64d1077..1de087d 100644 --- a/src/boilerplate-card.ts +++ b/src/boilerplate-card.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { LitElement, html, TemplateResult, css, PropertyValues, CSSResultGroup } from 'lit'; -import { customElement, property, state } from 'lit/decorators'; +import { customElement, property, state } from 'lit/decorators.js'; import { HomeAssistant, hasConfigOrEntityChanged, diff --git a/src/editor.ts b/src/editor.ts index 00ae2cb..949585f 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -1,17 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { LitElement, html, TemplateResult, css, CSSResultGroup } from 'lit'; +import { LitElement, html, TemplateResult, css } from 'lit'; import { HomeAssistant, fireEvent, LovelaceCardEditor } from 'custom-card-helpers'; -import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin'; import { BoilerplateCardConfig } from './types'; -import { customElement, property, state } from 'lit/decorators'; -import { formfieldDefinition } from '../elements/formfield'; -import { selectDefinition } from '../elements/select'; -import { switchDefinition } from '../elements/switch'; -import { textfieldDefinition } from '../elements/textfield'; +import { customElement, property, state } from 'lit/decorators.js'; +import { PluginStyles } from './styles/styles'; @customElement('boilerplate-card-editor') -export class BoilerplateCardEditor extends ScopedRegistryHost(LitElement) implements LovelaceCardEditor { +export class BoilerplateCardEditor extends LitElement implements LovelaceCardEditor { @property({ attribute: false }) public hass?: HomeAssistant; @state() private _config?: BoilerplateCardConfig; @@ -20,13 +16,6 @@ export class BoilerplateCardEditor extends ScopedRegistryHost(LitElement) implem private _initialized = false; - static elementDefinitions = { - ...textfieldDefinition, - ...selectDefinition, - ...switchDefinition, - ...formfieldDefinition, - }; - public setConfig(config: BoilerplateCardConfig): void { this._config = config; @@ -49,6 +38,10 @@ export class BoilerplateCardEditor extends ScopedRegistryHost(LitElement) implem return this._config?.entity || ''; } + get _area(): string { + return this._config?.area || ''; + } + get _show_warning(): boolean { return this._config?.show_warning || false; } @@ -66,39 +59,47 @@ export class BoilerplateCardEditor extends ScopedRegistryHost(LitElement) implem const entities = Object.keys(this.hass.states); return html` - ev.stopPropagation()} > - ${entities.map((entity) => { - return html`${entity}`; - })} - - html` ${entity} `)} + + + + - - + + - - - + + + - + > + `; } @@ -136,17 +137,23 @@ export class BoilerplateCardEditor extends ScopedRegistryHost(LitElement) implem fireEvent(this, 'config-changed', { config: this._config }); } - static styles: CSSResultGroup = css` - mwc-select, - mwc-textfield { - margin-bottom: 16px; - display: block; - } - mwc-formfield { - padding-bottom: 8px; - } - mwc-switch { - --mdc-theme-secondary: var(--switch-checked-color); - } - `; + static get styles() { + return [ + PluginStyles, + css` + ha-select, + mwc-select, + mwc-textfield { + margin-bottom: 16px; + display: block; + } + mwc-formfield { + padding-bottom: 8px; + } + mwc-switch { + --mdc-theme-secondary: var(--switch-checked-color); + } + `, + ]; + } } diff --git a/src/types.ts b/src/types.ts index 9a5e863..a2fe929 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,6 +15,7 @@ export interface BoilerplateCardConfig extends LovelaceCardConfig { show_error?: boolean; test_gui?: boolean; entity?: string; + area?: string; tap_action?: ActionConfig; hold_action?: ActionConfig; double_tap_action?: ActionConfig;