20230330.0 (#15982)

This commit is contained in:
Bram Kragten 2023-03-30 17:08:04 +02:00 committed by GitHub
commit 4483a8b9a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 483 additions and 366 deletions

View File

@ -20,7 +20,7 @@
"settings": { "settings": {
"import/resolver": { "import/resolver": {
"webpack": { "webpack": {
"config": "./webpack.config.js" "config": "./webpack.config.cjs"
} }
} }
}, },

View File

@ -43,7 +43,7 @@ jobs:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }} LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
- name: Bump version - name: Bump version
run: script/version_bump.js nightly run: script/version_bump.cjs nightly
- name: Build nightly Python wheels - name: Build nightly Python wheels
run: | run: |

View File

@ -1,6 +1,6 @@
const path = require("path"); const path = require("path");
const env = require("./env.js"); const env = require("./env.cjs");
const paths = require("./paths.js"); const paths = require("./paths.cjs");
// GitHub base URL to use for production source maps // GitHub base URL to use for production source maps
// Nightly builds use the commit SHA, otherwise assumes there is a tag that matches the version // Nightly builds use the commit SHA, otherwise assumes there is a tag that matches the version
@ -99,7 +99,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
[ [
path.resolve( path.resolve(
paths.polymer_dir, paths.polymer_dir,
"build-scripts/babel-plugins/inline-constants-plugin.js" "build-scripts/babel-plugins/inline-constants-plugin.cjs"
), ),
{ {
modules: ["@mdi/js"], modules: ["@mdi/js"],

View File

@ -1,6 +1,6 @@
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const paths = require("./paths.js"); const paths = require("./paths.cjs");
module.exports = { module.exports = {
useRollup() { useRollup() {

View File

@ -1,18 +1,18 @@
// Run HA develop mode // Run HA develop mode
const gulp = require("gulp"); const gulp = require("gulp");
const env = require("../env"); const env = require("../env.cjs");
require("./clean.js"); require("./clean.cjs");
require("./translations.js"); require("./translations.cjs");
require("./locale-data.js"); require("./locale-data.cjs");
require("./gen-icons-json.js"); require("./gen-icons-json.cjs");
require("./gather-static.js"); require("./gather-static.cjs");
require("./compress.js"); require("./compress.cjs");
require("./webpack.js"); require("./webpack.cjs");
require("./service-worker.js"); require("./service-worker.cjs");
require("./entry-html.js"); require("./entry-html.cjs");
require("./rollup.js"); require("./rollup.cjs");
require("./wds.js"); require("./wds.cjs");
gulp.task( gulp.task(
"develop-app", "develop-app",

View File

@ -1,14 +1,13 @@
const gulp = require("gulp"); const gulp = require("gulp");
const env = require("../env.cjs");
const env = require("../env"); require("./clean.cjs");
require("./translations.cjs");
require("./clean.js"); require("./gather-static.cjs");
require("./translations.js"); require("./webpack.cjs");
require("./gather-static.js"); require("./service-worker.cjs");
require("./webpack.js"); require("./entry-html.cjs");
require("./service-worker.js"); require("./rollup.cjs");
require("./entry-html.js");
require("./rollup.js");
gulp.task( gulp.task(
"develop-cast", "develop-cast",

View File

@ -1,7 +1,7 @@
const del = import("del"); const del = import("del");
const gulp = require("gulp"); const gulp = require("gulp");
const paths = require("../paths"); const paths = require("../paths.cjs");
require("./translations"); require("./translations.cjs");
gulp.task( gulp.task(
"clean", "clean",

View File

@ -4,7 +4,7 @@ const gulp = require("gulp");
const zopfli = require("gulp-zopfli-green"); const zopfli = require("gulp-zopfli-green");
const merge = require("merge-stream"); const merge = require("merge-stream");
const path = require("path"); const path = require("path");
const paths = require("../paths"); const paths = require("../paths.cjs");
const zopfliOptions = { threshold: 150 }; const zopfliOptions = { threshold: 150 };

View File

@ -1,16 +1,15 @@
// Run demo develop mode // Run demo develop mode
const gulp = require("gulp"); const gulp = require("gulp");
const env = require("../env.cjs");
const env = require("../env"); require("./clean.cjs");
require("./translations.cjs");
require("./clean.js"); require("./gen-icons-json.cjs");
require("./translations.js"); require("./gather-static.cjs");
require("./gen-icons-json.js"); require("./webpack.cjs");
require("./gather-static.js"); require("./service-worker.cjs");
require("./webpack.js"); require("./entry-html.cjs");
require("./service-worker.js"); require("./rollup.cjs");
require("./entry-html.js");
require("./rollup.js");
gulp.task( gulp.task(
"develop-demo", "develop-demo",

View File

@ -4,9 +4,9 @@ const fs = require("fs-extra");
const path = require("path"); const path = require("path");
const template = require("lodash.template"); const template = require("lodash.template");
const { minify } = require("html-minifier-terser"); const { minify } = require("html-minifier-terser");
const paths = require("../paths.js"); const paths = require("../paths.cjs");
const env = require("../env.js"); const env = require("../env.cjs");
const { htmlMinifierOptions, terserOptions } = require("../bundle.js"); const { htmlMinifierOptions, terserOptions } = require("../bundle.cjs");
const templatePath = (tpl) => const templatePath = (tpl) =>
path.resolve(paths.polymer_dir, "src/html/", `${tpl}.html.template`); path.resolve(paths.polymer_dir, "src/html/", `${tpl}.html.template`);

View File

@ -6,17 +6,17 @@ const { marked } = require("marked");
const glob = require("glob"); const glob = require("glob");
const yaml = require("js-yaml"); const yaml = require("js-yaml");
const env = require("../env"); const env = require("../env.cjs");
const paths = require("../paths"); const paths = require("../paths.cjs");
require("./clean.js"); require("./clean.cjs");
require("./translations.js"); require("./translations.cjs");
require("./gen-icons-json.js"); require("./gen-icons-json.cjs");
require("./gather-static.js"); require("./gather-static.cjs");
require("./webpack.js"); require("./webpack.cjs");
require("./service-worker.js"); require("./service-worker.cjs");
require("./entry-html.js"); require("./entry-html.cjs");
require("./rollup.js"); require("./rollup.cjs");
gulp.task("gather-gallery-pages", async function gatherPages() { gulp.task("gather-gallery-pages", async function gatherPages() {
const pageDir = path.resolve(paths.gallery_dir, "src/pages"); const pageDir = path.resolve(paths.gallery_dir, "src/pages");
@ -89,9 +89,7 @@ gulp.task("gather-gallery-pages", async function gatherPages() {
// Generate sidebar // Generate sidebar
const sidebarPath = path.resolve(paths.gallery_dir, "sidebar.js"); const sidebarPath = path.resolve(paths.gallery_dir, "sidebar.js");
// To make watch work during development const sidebar = (await import(sidebarPath)).default;
delete require.cache[sidebarPath];
const sidebar = require(sidebarPath);
const pagesToProcess = {}; const pagesToProcess = {};
for (const key of processed) { for (const key of processed) {

View File

@ -3,7 +3,7 @@
const gulp = require("gulp"); const gulp = require("gulp");
const path = require("path"); const path = require("path");
const fs = require("fs-extra"); const fs = require("fs-extra");
const paths = require("../paths"); const paths = require("../paths.cjs");
const npmPath = (...parts) => const npmPath = (...parts) =>
path.resolve(paths.polymer_dir, "node_modules", ...parts); path.resolve(paths.polymer_dir, "node_modules", ...parts);

View File

@ -134,11 +134,11 @@ gulp.task("gen-icons-json", (done) => {
}); });
const file = fs.readFileSync(PACKAGE_PATH, { encoding }); const file = fs.readFileSync(PACKAGE_PATH, { encoding });
const package = JSON.parse(file); const packageMeta = JSON.parse(file);
fs.writeFileSync( fs.writeFileSync(
path.resolve(OUTPUT_DIR, "iconMetadata.json"), path.resolve(OUTPUT_DIR, "iconMetadata.json"),
JSON.stringify({ version: package.version, parts }) JSON.stringify({ version: packageMeta.version, parts })
); );
fs.writeFileSync( fs.writeFileSync(

View File

@ -1,13 +1,13 @@
const gulp = require("gulp"); const gulp = require("gulp");
const env = require("../env"); const env = require("../env.cjs");
require("./clean.js"); require("./clean.cjs");
require("./gen-icons-json.js"); require("./compress.cjs");
require("./webpack.js"); require("./entry-html.cjs");
require("./compress.js"); require("./gather-static.cjs");
require("./rollup.js"); require("./gen-icons-json.cjs");
require("./gather-static.js"); require("./rollup.cjs");
require("./translations.js"); require("./translations.cjs");
require("./gen-icons-json.js"); require("./webpack.cjs");
gulp.task( gulp.task(
"develop-hassio", "develop-hassio",

View File

@ -2,7 +2,7 @@ const del = import("del");
const path = require("path"); const path = require("path");
const gulp = require("gulp"); const gulp = require("gulp");
const fs = require("fs"); const fs = require("fs");
const paths = require("../paths"); const paths = require("../paths.cjs");
const outDir = "build/locale-data"; const outDir = "build/locale-data";

View File

@ -6,8 +6,8 @@ const handler = require("serve-handler");
const http = require("http"); const http = require("http");
const log = require("fancy-log"); const log = require("fancy-log");
const open = require("open"); const open = require("open");
const rollupConfig = require("../rollup"); const rollupConfig = require("../rollup.cjs");
const paths = require("../paths"); const paths = require("../paths.cjs");
const bothBuilds = (createConfigFunc, params) => const bothBuilds = (createConfigFunc, params) =>
gulp.series( gulp.series(
@ -46,7 +46,7 @@ function createServer(serveOptions) {
); );
} }
function watchRollup(createConfig, extraWatchSrc = [], serveOptions) { function watchRollup(createConfig, extraWatchSrc = [], serveOptions = null) {
const { inputOptions, outputOptions } = createConfig({ const { inputOptions, outputOptions } = createConfig({
isProdBuild: false, isProdBuild: false,
latestBuild: true, latestBuild: true,

View File

@ -5,7 +5,7 @@ const path = require("path");
const fs = require("fs-extra"); const fs = require("fs-extra");
const workboxBuild = require("workbox-build"); const workboxBuild = require("workbox-build");
const sourceMapUrl = require("source-map-url"); const sourceMapUrl = require("source-map-url");
const paths = require("../paths.js"); const paths = require("../paths.cjs");
const swDest = path.resolve(paths.app_output_root, "service_worker.js"); const swDest = path.resolve(paths.app_output_root, "service_worker.js");

View File

@ -9,11 +9,11 @@ const flatmap = require("gulp-flatmap");
const merge = require("gulp-merge-json"); const merge = require("gulp-merge-json");
const rename = require("gulp-rename"); const rename = require("gulp-rename");
const transform = require("gulp-json-transform"); const transform = require("gulp-json-transform");
const { mapFiles } = require("../util"); const { mapFiles } = require("../util.cjs");
const env = require("../env"); const env = require("../env.cjs");
const paths = require("../paths"); const paths = require("../paths.cjs");
require("./fetch-nightly-translations"); require("./fetch-nightly-translations.cjs");
const inFrontendDir = "translations/frontend"; const inFrontendDir = "translations/frontend";
const inBackendDir = "translations/backend"; const inBackendDir = "translations/backend";

View File

@ -5,15 +5,15 @@ const webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server"); const WebpackDevServer = require("webpack-dev-server");
const log = require("fancy-log"); const log = require("fancy-log");
const path = require("path"); const path = require("path");
const env = require("../env"); const env = require("../env.cjs");
const paths = require("../paths"); const paths = require("../paths.cjs");
const { const {
createAppConfig, createAppConfig,
createDemoConfig, createDemoConfig,
createCastConfig, createCastConfig,
createHassioConfig, createHassioConfig,
createGalleryConfig, createGalleryConfig,
} = require("../webpack"); } = require("../webpack.cjs");
const bothBuilds = (createConfigFunc, params) => [ const bothBuilds = (createConfigFunc, params) => [
createConfigFunc({ ...params, latestBuild: true }), createConfigFunc({ ...params, latestBuild: true }),

View File

@ -103,7 +103,7 @@ module.exports = function (opts = {}) {
} }
delete optionsObject.type; delete optionsObject.type;
if (!new RegExp("^.*/").test(workerFile)) { if (!/^.*\//.test(workerFile)) {
this.warn( this.warn(
`Paths passed to the Worker constructor must be relative or absolute, i.e. start with /, ./ or ../ (just like dynamic import!). Ignoring "${workerFile}".` `Paths passed to the Worker constructor must be relative or absolute, i.e. start with /, ./ or ../ (just like dynamic import!). Ignoring "${workerFile}".`
); );

View File

@ -3,18 +3,18 @@ const path = require("path");
const commonjs = require("@rollup/plugin-commonjs"); const commonjs = require("@rollup/plugin-commonjs");
const resolve = require("@rollup/plugin-node-resolve"); const resolve = require("@rollup/plugin-node-resolve");
const json = require("@rollup/plugin-json"); const json = require("@rollup/plugin-json");
const babel = require("@rollup/plugin-babel").babel; const { babel } = require("@rollup/plugin-babel");
const replace = require("@rollup/plugin-replace"); const replace = require("@rollup/plugin-replace");
const visualizer = require("rollup-plugin-visualizer"); const visualizer = require("rollup-plugin-visualizer");
const { string } = require("rollup-plugin-string"); const { string } = require("rollup-plugin-string");
const { terser } = require("rollup-plugin-terser"); const { terser } = require("rollup-plugin-terser");
const manifest = require("./rollup-plugins/manifest-plugin"); const manifest = require("./rollup-plugins/manifest-plugin.cjs");
const worker = require("./rollup-plugins/worker-plugin"); const worker = require("./rollup-plugins/worker-plugin.cjs");
const dontHashPlugin = require("./rollup-plugins/dont-hash-plugin"); const dontHashPlugin = require("./rollup-plugins/dont-hash-plugin.cjs");
const ignore = require("./rollup-plugins/ignore-plugin"); const ignore = require("./rollup-plugins/ignore-plugin.cjs");
const bundle = require("./bundle"); const bundle = require("./bundle.cjs");
const paths = require("./paths"); const paths = require("./paths.cjs");
const extensions = [".js", ".ts"]; const extensions = [".js", ".ts"];

View File

@ -4,8 +4,8 @@ const TerserPlugin = require("terser-webpack-plugin");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin"); const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const log = require("fancy-log"); const log = require("fancy-log");
const WebpackBar = require("webpackbar"); const WebpackBar = require("webpackbar");
const paths = require("./paths.js"); const paths = require("./paths.cjs");
const bundle = require("./bundle.js"); const bundle = require("./bundle.cjs");
class LogStartCompilePlugin { class LogStartCompilePlugin {
ignoredFirst = false; ignoredFirst = false;
@ -64,6 +64,9 @@ const createWebpackConfig = ({
cacheCompression: false, cacheCompression: false,
}, },
}, },
resolve: {
fullySpecified: false,
},
}, },
{ {
test: /\.css$/, test: /\.css$/,

View File

@ -1,5 +1,5 @@
const rollup = require("../build-scripts/rollup.js"); import rollup from "../build-scripts/rollup.cjs";
const env = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
const config = rollup.createCastConfig({ const config = rollup.createCastConfig({
isProdBuild: env.isProdBuild(), isProdBuild: env.isProdBuild(),
@ -7,4 +7,4 @@ const config = rollup.createCastConfig({
isStatsBuild: env.isStatsBuild(), isStatsBuild: env.isStatsBuild(),
}); });
module.exports = { ...config.inputOptions, output: config.outputOptions }; export default { ...config.inputOptions, output: config.outputOptions };

View File

@ -1,8 +1,8 @@
const { createCastConfig } = require("../build-scripts/webpack.js"); import webpack from "../build-scripts/webpack.cjs";
const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
module.exports = createCastConfig({ export default webpack.createCastConfig({
isProdBuild: isProdBuild(), isProdBuild: env.isProdBuild(),
isStatsBuild: isStatsBuild(), isStatsBuild: env.isStatsBuild(),
latestBuild: true, latestBuild: true,
}); });

View File

@ -1,5 +1,5 @@
const rollup = require("../build-scripts/rollup.js"); import rollup from "../build-scripts/rollup.cjs";
const env = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
const config = rollup.createDemoConfig({ const config = rollup.createDemoConfig({
isProdBuild: env.isProdBuild(), isProdBuild: env.isProdBuild(),
@ -7,4 +7,4 @@ const config = rollup.createDemoConfig({
isStatsBuild: env.isStatsBuild(), isStatsBuild: env.isStatsBuild(),
}); });
module.exports = { ...config.inputOptions, output: config.outputOptions }; export default { ...config.inputOptions, output: config.outputOptions };

View File

@ -1,12 +1,11 @@
const { createDemoConfig } = require("../build-scripts/webpack.js"); import webpack from "../build-scripts/webpack.cjs";
const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
// File just used for stats builds // File just used for stats builds
const latestBuild = true; const latestBuild = true;
module.exports = createDemoConfig({ export default webpack.createDemoConfig({
isProdBuild: isProdBuild(), isProdBuild: env.isProdBuild(),
isStatsBuild: isStatsBuild(), isStatsBuild: env.isStatsBuild(),
latestBuild, latestBuild,
}); });

View File

@ -1,5 +1,5 @@
const rollup = require("../build-scripts/rollup.js"); import rollup from "../build-scripts/rollup.cjs";
const env = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
const config = rollup.createGalleryConfig({ const config = rollup.createGalleryConfig({
isProdBuild: env.isProdBuild(), isProdBuild: env.isProdBuild(),
@ -7,4 +7,4 @@ const config = rollup.createGalleryConfig({
isStatsBuild: env.isStatsBuild(), isStatsBuild: env.isStatsBuild(),
}); });
module.exports = { ...config.inputOptions, output: config.outputOptions }; export default { ...config.inputOptions, output: config.outputOptions };

View File

@ -1,4 +1,4 @@
module.exports = [ export default [
{ {
// This section has no header and so all page links are shown directly in the sidebar // This section has no header and so all page links are shown directly in the sidebar
category: "concepts", category: "concepts",

View File

@ -1,8 +1,8 @@
const { createGalleryConfig } = require("../build-scripts/webpack.js"); import webpack from "../build-scripts/webpack.cjs";
const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
module.exports = createGalleryConfig({ export default webpack.createGalleryConfig({
isProdBuild: isProdBuild(), isProdBuild: env.isProdBuild(),
isStatsBuild: isStatsBuild(), isStatsBuild: env.isStatsBuild(),
latestBuild: true, latestBuild: true,
}); });

View File

@ -1,3 +1,13 @@
var requireDir = require("require-dir"); import { globIterate } from "glob";
requireDir("./build-scripts/gulp/"); const gulpImports = [];
for await (const gulpModule of globIterate("build-scripts/gulp/*.?(c|m)js", {
dotRelative: true,
})) {
gulpImports.push(import(gulpModule));
}
// Since all tasks are currently registered with gulp.task(), this is enough
// If any are converted to named exports, need to loop and aggregate exports here
await Promise.all(gulpImports);

View File

@ -1,5 +1,5 @@
const rollup = require("../build-scripts/rollup.js"); import rollup from "../build-scripts/rollup.cjs";
const env = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
const config = rollup.createHassioConfig({ const config = rollup.createHassioConfig({
isProdBuild: env.isProdBuild(), isProdBuild: env.isProdBuild(),
@ -7,4 +7,4 @@ const config = rollup.createHassioConfig({
isStatsBuild: env.isStatsBuild(), isStatsBuild: env.isStatsBuild(),
}); });
module.exports = { ...config.inputOptions, output: config.outputOptions }; export default { ...config.inputOptions, output: config.outputOptions };

View File

@ -1,8 +1,8 @@
const { createHassioConfig } = require("../build-scripts/webpack.js"); import webpack from "../build-scripts/webpack.cjs";
const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js"); import env from "../build-scripts/env.cjs";
module.exports = createHassioConfig({ export default webpack.createHassioConfig({
isProdBuild: isProdBuild(), isProdBuild: env.isProdBuild(),
isStatsBuild: isStatsBuild(), isStatsBuild: env.isStatsBuild(),
latestBuild: true, latestBuild: true,
}); });

View File

@ -1,5 +1,5 @@
module.exports = { export default {
"*.{js,ts}": ["prettier --write", "eslint --fix"], "*.?(c|m){js,ts}": ["eslint --fix", "prettier --write"],
"!(/translations)*.{json,css,md,html}": "prettier --write", "!(/translations)*.{json,css,md,html}": "prettier --write",
"translations/*/*.json": (files) => "translations/*/*.json": (files) =>
'printf "%s\n" "Translation files should not be added or modified here. Instead, make the necessary modifications in src/translations/en.json. Other languages are managed externally. Please see https://developers.home-assistant.io/docs/translations/ for details." ' + 'printf "%s\n" "Translation files should not be added or modified here. Instead, make the necessary modifications in src/translations/en.json. Other languages are managed externally. Please see https://developers.home-assistant.io/docs/translations/ for details." ' +

View File

@ -19,10 +19,11 @@
"postinstall": "husky install", "postinstall": "husky install",
"prepack": "pinst --disable", "prepack": "pinst --disable",
"postpack": "pinst --enable", "postpack": "pinst --enable",
"test": "instant-mocha --webpack-config ./test/webpack.config.js --require ./test/setup.js \"test/**/*.ts\"" "test": "instant-mocha --webpack-config ./test/webpack.config.js --require ./test/setup.cjs \"test/**/*.ts\""
}, },
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)", "author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module",
"dependencies": { "dependencies": {
"@braintree/sanitize-url": "6.0.2", "@braintree/sanitize-url": "6.0.2",
"@codemirror/autocomplete": "6.4.2", "@codemirror/autocomplete": "6.4.2",
@ -227,13 +228,12 @@
"open": "8.4.2", "open": "8.4.2",
"pinst": "3.0.0", "pinst": "3.0.0",
"prettier": "2.8.7", "prettier": "2.8.7",
"require-dir": "1.2.0",
"rollup": "2.79.1", "rollup": "2.79.1",
"rollup-plugin-string": "3.0.0", "rollup-plugin-string": "3.0.0",
"rollup-plugin-terser": "7.0.2", "rollup-plugin-terser": "7.0.2",
"rollup-plugin-visualizer": "5.9.0", "rollup-plugin-visualizer": "5.9.0",
"serve-handler": "6.1.5", "serve-handler": "6.1.5",
"sinon": "15.0.2", "sinon": "15.0.3",
"source-map-url": "0.4.1", "source-map-url": "0.4.1",
"systemjs": "6.14.1", "systemjs": "6.14.1",
"tar": "6.1.13", "tar": "6.1.13",
@ -254,7 +254,6 @@
"@polymer/polymer": "patch:@polymer/polymer@3.5.1#./.yarn/patches/@polymer/polymer/pr-5569.patch", "@polymer/polymer": "patch:@polymer/polymer@3.5.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
"@material/mwc-button@^0.25.3": "^0.27.0" "@material/mwc-button@^0.25.3": "^0.27.0"
}, },
"main": "src/home-assistant.js",
"prettier": { "prettier": {
"trailingComma": "es5", "trailingComma": "es5",
"arrowParens": "always" "arrowParens": "always"

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "home-assistant-frontend" name = "home-assistant-frontend"
version = "20230329.0" version = "20230330.0"
license = {text = "Apache-2.0"} license = {text = "Apache-2.0"}
description = "The Home Assistant frontend" description = "The Home Assistant frontend"
readme = "README.md" readme = "README.md"

View File

@ -1,5 +1,5 @@
const rollup = require("./build-scripts/rollup.js"); import rollup from "../build-scripts/rollup.cjs";
const env = require("./build-scripts/env.js"); import env from "../build-scripts/env.cjs";
const config = rollup.createAppConfig({ const config = rollup.createAppConfig({
isProdBuild: env.isProdBuild(), isProdBuild: env.isProdBuild(),
@ -7,4 +7,4 @@ const config = rollup.createAppConfig({
isStatsBuild: env.isStatsBuild(), isStatsBuild: env.isStatsBuild(),
}); });
module.exports = { ...config.inputOptions, output: config.outputOptions }; export default { ...config.inputOptions, output: config.outputOptions };

View File

@ -302,6 +302,7 @@ export default class HaChartBase extends LitElement {
return css` return css`
:host { :host {
display: block; display: block;
position: relative;
} }
.chartContainer { .chartContainer {
overflow: hidden; overflow: hidden;

View File

@ -61,6 +61,10 @@ class StateHistoryChartLine extends LitElement {
this._chartOptions = { this._chartOptions = {
parsing: false, parsing: false,
animation: false, animation: false,
interaction: {
mode: "nearest",
axis: "x",
},
scales: { scales: {
x: { x: {
type: "time", type: "time",
@ -108,7 +112,6 @@ class StateHistoryChartLine extends LitElement {
}, },
plugins: { plugins: {
tooltip: { tooltip: {
mode: "nearest",
callbacks: { callbacks: {
label: (context) => label: (context) =>
`${context.dataset.label}: ${formatNumber( `${context.dataset.label}: ${formatNumber(
@ -127,16 +130,13 @@ class StateHistoryChartLine extends LitElement {
}, },
}, },
}, },
hover: {
mode: "nearest",
},
elements: { elements: {
line: { line: {
tension: 0.1, tension: 0.1,
borderWidth: 1.5, borderWidth: 1.5,
}, },
point: { point: {
hitRadius: 5, hitRadius: 50,
}, },
}, },
// @ts-expect-error // @ts-expect-error

View File

@ -102,6 +102,7 @@ class StatisticsChart extends LitElement {
if ( if (
changedProps.has("statisticsData") || changedProps.has("statisticsData") ||
changedProps.has("statTypes") || changedProps.has("statTypes") ||
changedProps.has("chartType") ||
changedProps.has("hideLegend") changedProps.has("hideLegend")
) { ) {
this._generateData(); this._generateData();
@ -149,6 +150,10 @@ class StatisticsChart extends LitElement {
this._chartOptions = { this._chartOptions = {
parsing: false, parsing: false,
animation: false, animation: false,
interaction: {
mode: "nearest",
axis: "x",
},
scales: { scales: {
x: { x: {
type: "time", type: "time",
@ -186,7 +191,6 @@ class StatisticsChart extends LitElement {
}, },
plugins: { plugins: {
tooltip: { tooltip: {
mode: "nearest",
callbacks: { callbacks: {
label: (context) => label: (context) =>
`${context.dataset.label}: ${formatNumber( `${context.dataset.label}: ${formatNumber(
@ -208,9 +212,6 @@ class StatisticsChart extends LitElement {
}, },
}, },
}, },
hover: {
mode: "nearest",
},
elements: { elements: {
line: { line: {
tension: 0.4, tension: 0.4,
@ -219,7 +220,7 @@ class StatisticsChart extends LitElement {
}, },
bar: { borderWidth: 1.5, borderRadius: 4 }, bar: { borderWidth: 1.5, borderRadius: 4 },
point: { point: {
hitRadius: 5, hitRadius: 50,
}, },
}, },
// @ts-expect-error // @ts-expect-error
@ -316,6 +317,7 @@ class StatisticsChart extends LitElement {
} }
statDataSets.forEach((d, i) => { statDataSets.forEach((d, i) => {
if ( if (
this.chartType === "line" &&
prevEndTime && prevEndTime &&
prevValues && prevValues &&
prevEndTime.getTime() !== start.getTime() prevEndTime.getTime() !== start.getTime()

View File

@ -41,7 +41,9 @@ export class HaDialog extends DialogBase {
SUPPRESS_DEFAULT_PRESS_SELECTOR, SUPPRESS_DEFAULT_PRESS_SELECTOR,
].join(", "); ].join(", ");
this._updateScrolledAttribute(); this._updateScrolledAttribute();
this.contentElement?.addEventListener("scroll", this._onScroll); this.contentElement?.addEventListener("scroll", this._onScroll, {
passive: true,
});
} }
disconnectedCallback(): void { disconnectedCallback(): void {

View File

@ -191,6 +191,9 @@ export class HaFileUpload extends LitElement {
inset-inline-end: initial !important; inset-inline-end: initial !important;
direction: var(--direction); direction: var(--direction);
} }
.mdc-text-field__icon--trailing {
pointer-events: auto !important;
}
.dragged:before { .dragged:before {
position: var(--layout-fit_-_position); position: var(--layout-fit_-_position);
top: var(--layout-fit_-_top); top: var(--layout-fit_-_top);

View File

@ -10,6 +10,7 @@ export class HaTopAppBarFixed extends TopAppBarFixedBase {
css` css`
.mdc-top-app-bar__row { .mdc-top-app-bar__row {
height: var(--header-height); height: var(--header-height);
border-bottom: var(--app-header-border-bottom);
} }
.mdc-top-app-bar--fixed-adjust { .mdc-top-app-bar--fixed-adjust {
padding-top: var(--header-height); padding-top: var(--header-height);
@ -21,7 +22,6 @@ export class HaTopAppBarFixed extends TopAppBarFixedBase {
--app-header-background-color, --app-header-background-color,
var(--mdc-theme-primary) var(--mdc-theme-primary)
); );
border-bottom: var(--app-header-border-bottom);
} }
`, `,
]; ];

View File

@ -10,6 +10,7 @@ export class HaTopAppBar extends TopAppBarBase {
css` css`
.mdc-top-app-bar__row { .mdc-top-app-bar__row {
height: var(--header-height); height: var(--header-height);
border-bottom: var(--app-header-border-bottom);
} }
.mdc-top-app-bar--fixed-adjust { .mdc-top-app-bar--fixed-adjust {
padding-top: var(--header-height); padding-top: var(--header-height);
@ -21,7 +22,6 @@ export class HaTopAppBar extends TopAppBarBase {
--app-header-background-color, --app-header-background-color,
var(--mdc-theme-primary) var(--mdc-theme-primary)
); );
border-bottom: var(--app-header-border-bottom);
} }
`, `,
]; ];

View File

@ -3,7 +3,9 @@ import {
HassEntityBase, HassEntityBase,
} from "home-assistant-js-websocket"; } from "home-assistant-js-websocket";
import { supportsFeature } from "../common/entity/supports-feature"; import { supportsFeature } from "../common/entity/supports-feature";
import { blankBeforePercent } from "../common/translations/blank_before_percent";
import { UNAVAILABLE } from "./entity"; import { UNAVAILABLE } from "./entity";
import { FrontendLocaleData } from "./translation";
export const enum CoverEntityFeature { export const enum CoverEntityFeature {
OPEN = 1, OPEN = 1,
@ -106,3 +108,18 @@ interface CoverEntityAttributes extends HassEntityAttributeBase {
export interface CoverEntity extends HassEntityBase { export interface CoverEntity extends HassEntityBase {
attributes: CoverEntityAttributes; attributes: CoverEntityAttributes;
} }
export function computeCoverPositionStateDisplay(
stateObj: CoverEntity,
locale: FrontendLocaleData,
position?: number
) {
const currentPosition =
position ??
stateObj.attributes.current_position ??
stateObj.attributes.current_tilt_position;
return currentPosition && currentPosition !== 100
? `${Math.round(currentPosition)}${blankBeforePercent(locale)}%`
: "";
}

View File

@ -9,6 +9,8 @@ import {
HassEntityAttributeBase, HassEntityAttributeBase,
HassEntityBase, HassEntityBase,
} from "home-assistant-js-websocket"; } from "home-assistant-js-websocket";
import { blankBeforePercent } from "../common/translations/blank_before_percent";
import { FrontendLocaleData } from "./translation";
export const enum FanEntityFeature { export const enum FanEntityFeature {
SET_SPEED = 1, SET_SPEED = 1,
@ -91,3 +93,15 @@ export function computeFanSpeedIcon(
: [mdiFanSpeed1, mdiFanSpeed2, mdiFanSpeed3][index - 1]; : [mdiFanSpeed1, mdiFanSpeed2, mdiFanSpeed3][index - 1];
} }
export const FAN_SPEED_COUNT_MAX_FOR_BUTTONS = 4; export const FAN_SPEED_COUNT_MAX_FOR_BUTTONS = 4;
export function computeFanSpeedStateDisplay(
stateObj: FanEntity,
locale: FrontendLocaleData,
speed?: number
) {
const currentSpeed = speed ?? stateObj.attributes.percentage;
return currentSpeed
? `${Math.round(currentSpeed)}${blankBeforePercent(locale)}%`
: "";
}

View File

@ -10,9 +10,12 @@ import {
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { computeStateDisplay } from "../../../common/entity/compute_state_display"; import { computeStateDisplay } from "../../../common/entity/compute_state_display";
import { supportsFeature } from "../../../common/entity/supports-feature"; import { supportsFeature } from "../../../common/entity/supports-feature";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
import "../../../components/ha-attributes"; import "../../../components/ha-attributes";
import { CoverEntity, CoverEntityFeature } from "../../../data/cover"; import {
computeCoverPositionStateDisplay,
CoverEntity,
CoverEntityFeature,
} from "../../../data/cover";
import type { HomeAssistant } from "../../../types"; import type { HomeAssistant } from "../../../types";
import "../components/cover/ha-more-info-cover-buttons"; import "../components/cover/ha-more-info-cover-buttons";
import "../components/cover/ha-more-info-cover-position"; import "../components/cover/ha-more-info-cover-position";
@ -27,7 +30,9 @@ class MoreInfoCover extends LitElement {
@property({ attribute: false }) public stateObj?: CoverEntity; @property({ attribute: false }) public stateObj?: CoverEntity;
@state() private _displayedPosition?: number; @state() private _livePosition?: number;
@state() private _liveTilt?: number;
@state() private _mode?: "position" | "button"; @state() private _mode?: "position" | "button";
@ -35,20 +40,29 @@ class MoreInfoCover extends LitElement {
this._mode = this._mode === "position" ? "button" : "position"; this._mode = this._mode === "position" ? "button" : "position";
} }
private _positionChanged(ev) { private _positionSliderMoved(ev) {
const value = (ev.detail as any).value; const value = (ev.detail as any).value;
if (isNaN(value)) return; if (isNaN(value)) return;
this._displayedPosition = value; this._livePosition = value;
}
private _positionValueChanged() {
this._livePosition = undefined;
}
private _tiltSliderMoved(ev) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._liveTilt = value;
}
private _tiltValueChanged() {
this._liveTilt = undefined;
} }
protected willUpdate(changedProps: PropertyValues): void { protected willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps); super.willUpdate(changedProps);
if (changedProps.has("stateObj") && this.stateObj) { if (changedProps.has("stateObj") && this.stateObj) {
if (supportsFeature(this.stateObj, CoverEntityFeature.SET_POSITION)) {
const currentPosition = this.stateObj?.attributes.current_position;
this._displayedPosition =
currentPosition != null ? Math.round(currentPosition) : undefined;
}
if (!this._mode) { if (!this._mode) {
this._mode = this._mode =
supportsFeature(this.stateObj, CoverEntityFeature.SET_POSITION) || supportsFeature(this.stateObj, CoverEntityFeature.SET_POSITION) ||
@ -60,29 +74,29 @@ class MoreInfoCover extends LitElement {
} }
private get _stateOverride() { private get _stateOverride() {
if (this._displayedPosition == null) return undefined; const liveValue = this._livePosition ?? this._liveTilt;
const tempState = { const forcedState =
...this.stateObj, liveValue != null ? (liveValue ? "open" : "closed") : undefined;
state: this._displayedPosition ? "open" : "closed",
attributes: {
...this.stateObj!.attributes,
current_position: this._displayedPosition,
},
} as CoverEntity;
const stateDisplay = computeStateDisplay( const stateDisplay = computeStateDisplay(
this.hass.localize, this.hass.localize,
tempState!, this.stateObj!,
this.hass.locale, this.hass.locale,
this.hass.entities this.hass.entities,
forcedState
); );
return this._displayedPosition && this._displayedPosition !== 100 const positionStateDisplay = computeCoverPositionStateDisplay(
? `${stateDisplay} - ${Math.round( this.stateObj!,
this._displayedPosition this.hass.locale,
)}${blankBeforePercent(this.hass!.locale)}%` liveValue
: stateDisplay; );
if (positionStateDisplay) {
return `${stateDisplay}${positionStateDisplay}`;
}
return stateDisplay;
} }
protected render() { protected render() {
@ -133,7 +147,8 @@ class MoreInfoCover extends LitElement {
<ha-more-info-cover-position <ha-more-info-cover-position
.stateObj=${this.stateObj} .stateObj=${this.stateObj}
.hass=${this.hass} .hass=${this.hass}
@slider-moved=${this._positionChanged} @slider-moved=${this._positionSliderMoved}
@value-changed=${this._positionValueChanged}
></ha-more-info-cover-position> ></ha-more-info-cover-position>
` `
: nothing} : nothing}
@ -142,6 +157,8 @@ class MoreInfoCover extends LitElement {
<ha-more-info-cover-tilt-position <ha-more-info-cover-tilt-position
.stateObj=${this.stateObj} .stateObj=${this.stateObj}
.hass=${this.hass} .hass=${this.hass}
@slider-moved=${this._tiltSliderMoved}
@value-changed=${this._tiltValueChanged}
></ha-more-info-cover-tilt-position> ></ha-more-info-cover-tilt-position>
` `
: nothing} : nothing}

View File

@ -22,11 +22,12 @@ import {
computeAttributeNameDisplay, computeAttributeNameDisplay,
computeAttributeValueDisplay, computeAttributeValueDisplay,
} from "../../../common/entity/compute_attribute_display"; } from "../../../common/entity/compute_attribute_display";
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
import { supportsFeature } from "../../../common/entity/supports-feature"; import { supportsFeature } from "../../../common/entity/supports-feature";
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
import "../../../components/ha-attributes"; import "../../../components/ha-attributes";
import { UNAVAILABLE } from "../../../data/entity"; import { UNAVAILABLE } from "../../../data/entity";
import { import {
computeFanSpeedStateDisplay,
computeFanSpeedCount, computeFanSpeedCount,
FanEntity, FanEntity,
FanEntityFeature, FanEntityFeature,
@ -49,12 +50,16 @@ class MoreInfoFan extends LitElement {
@state() public _presetMode?: string; @state() public _presetMode?: string;
@state() private _selectedPercentage?: number; @state() private _liveSpeed?: number;
private _percentageChanged(ev) { private _speedSliderMoved(ev) {
const value = (ev.detail as any).value; const value = (ev.detail as any).value;
if (isNaN(value)) return; if (isNaN(value)) return;
this._selectedPercentage = value; this._liveSpeed = value;
}
private _speedValueChanged() {
this._liveSpeed = undefined;
} }
private _toggle = () => { private _toggle = () => {
@ -107,12 +112,35 @@ class MoreInfoFan extends LitElement {
protected updated(changedProps: PropertyValues): void { protected updated(changedProps: PropertyValues): void {
if (changedProps.has("stateObj")) { if (changedProps.has("stateObj")) {
this._presetMode = this.stateObj?.attributes.preset_mode; this._presetMode = this.stateObj?.attributes.preset_mode;
this._selectedPercentage = this.stateObj?.attributes.percentage
? Math.round(this.stateObj.attributes.percentage)
: undefined;
} }
} }
private get _stateOverride() {
const liveValue = this._liveSpeed;
const forcedState =
this._liveSpeed != null ? (this._liveSpeed ? "on" : "off") : undefined;
const stateDisplay = computeStateDisplay(
this.hass.localize,
this.stateObj!,
this.hass.locale,
this.hass.entities,
forcedState
);
const positionStateDisplay = computeFanSpeedStateDisplay(
this.stateObj!,
this.hass.locale,
liveValue
);
if (positionStateDisplay) {
return positionStateDisplay;
}
return stateDisplay;
}
protected render() { protected render() {
if (!this.hass || !this.stateObj) { if (!this.hass || !this.stateObj) {
return nothing; return nothing;
@ -140,17 +168,11 @@ class MoreInfoFan extends LitElement {
supportsSpeed && supportsSpeed &&
computeFanSpeedCount(this.stateObj) > FAN_SPEED_COUNT_MAX_FOR_BUTTONS; computeFanSpeedCount(this.stateObj) > FAN_SPEED_COUNT_MAX_FOR_BUTTONS;
const stateOverride = this._selectedPercentage
? `${Math.round(this._selectedPercentage)}${blankBeforePercent(
this.hass!.locale
)}%`
: undefined;
return html` return html`
<ha-more-info-state-header <ha-more-info-state-header
.hass=${this.hass} .hass=${this.hass}
.stateObj=${this.stateObj} .stateObj=${this.stateObj}
.stateOverride=${stateOverride} .stateOverride=${this._stateOverride}
></ha-more-info-state-header> ></ha-more-info-state-header>
<div class="controls"> <div class="controls">
${ ${
@ -159,7 +181,8 @@ class MoreInfoFan extends LitElement {
<ha-more-info-fan-speed <ha-more-info-fan-speed
.stateObj=${this.stateObj} .stateObj=${this.stateObj}
.hass=${this.hass} .hass=${this.hass}
@slider-moved=${this._percentageChanged} @slider-moved=${this._speedSliderMoved}
@value-changed=${this._speedValueChanged}
> >
</ha-more-info-fan-speed> </ha-more-info-fan-speed>
` `

View File

@ -1,8 +1,6 @@
<meta name='viewport' content='width=device-width, user-scalable=no, viewport-fit=cover, initial-scale=1'> <meta name='viewport' content='width=device-width, user-scalable=no, viewport-fit=cover, initial-scale=1'>
<style> <style>
html {
overflow: hidden;
}
body { body {
font-family: Roboto, sans-serif; font-family: Roboto, sans-serif;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;

View File

@ -65,7 +65,7 @@ class HassErrorScreen extends LitElement {
align-items: center; align-items: center;
font-size: 20px; font-size: 20px;
height: var(--header-height); height: var(--header-height);
padding: 0 16px; padding: 8px 12px;
pointer-events: none; pointer-events: none;
background-color: var(--app-header-background-color); background-color: var(--app-header-background-color);
font-weight: 400; font-weight: 400;
@ -73,6 +73,11 @@ class HassErrorScreen extends LitElement {
border-bottom: var(--app-header-border-bottom, none); border-bottom: var(--app-header-border-bottom, none);
box-sizing: border-box; box-sizing: border-box;
} }
@media (max-width: 599px) {
.toolbar {
padding: 4px;
}
}
ha-icon-button-arrow-prev { ha-icon-button-arrow-prev {
pointer-events: auto; pointer-events: auto;
} }

View File

@ -60,7 +60,7 @@ class HassLoadingScreen extends LitElement {
align-items: center; align-items: center;
font-size: 20px; font-size: 20px;
height: var(--header-height); height: var(--header-height);
padding: 0 16px; padding: 8px 12px;
pointer-events: none; pointer-events: none;
background-color: var(--app-header-background-color); background-color: var(--app-header-background-color);
font-weight: 400; font-weight: 400;
@ -68,6 +68,11 @@ class HassLoadingScreen extends LitElement {
border-bottom: var(--app-header-border-bottom, none); border-bottom: var(--app-header-border-bottom, none);
box-sizing: border-box; box-sizing: border-box;
} }
@media (max-width: 599px) {
.toolbar {
padding: 4px;
}
}
ha-menu-button, ha-menu-button,
ha-icon-button-arrow-prev { ha-icon-button-arrow-prev {
pointer-events: auto; pointer-events: auto;

View File

@ -111,7 +111,7 @@ class HassSubpage extends LitElement {
align-items: center; align-items: center;
font-size: 20px; font-size: 20px;
height: var(--header-height); height: var(--header-height);
padding: 0 16px; padding: 8px 12px;
pointer-events: none; pointer-events: none;
background-color: var(--app-header-background-color); background-color: var(--app-header-background-color);
font-weight: 400; font-weight: 400;
@ -119,6 +119,11 @@ class HassSubpage extends LitElement {
border-bottom: var(--app-header-border-bottom, none); border-bottom: var(--app-header-border-bottom, none);
box-sizing: border-box; box-sizing: border-box;
} }
@media (max-width: 599px) {
.toolbar {
padding: 4px;
}
}
.toolbar a { .toolbar a {
color: var(--sidebar-text-color); color: var(--sidebar-text-color);
text-decoration: none; text-decoration: none;

View File

@ -323,7 +323,6 @@ export class HaTabsSubpageDataTable extends LitElement {
--text-field-overflow: initial; --text-field-overflow: initial;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-right: 8px;
color: var(--primary-text-color); color: var(--primary-text-color);
} }
.active-filters { .active-filters {

View File

@ -235,9 +235,14 @@ class HassTabsSubpage extends LitElement {
background-color: var(--sidebar-background-color); background-color: var(--sidebar-background-color);
font-weight: 400; font-weight: 400;
border-bottom: 1px solid var(--divider-color); border-bottom: 1px solid var(--divider-color);
padding: 0 16px; padding: 8px 12px;
box-sizing: border-box; box-sizing: border-box;
} }
@media (max-width: 599px) {
.toolbar {
padding: 4px;
}
}
.toolbar a { .toolbar a {
color: var(--sidebar-text-color); color: var(--sidebar-text-color);
text-decoration: none; text-decoration: none;

View File

@ -142,10 +142,12 @@ export class HomeAssistantMain extends LitElement {
protected updated(changedProps: PropertyValues) { protected updated(changedProps: PropertyValues) {
super.updated(changedProps); super.updated(changedProps);
toggleAttribute(this, "expanded", this.hass.dockedSidebar === "docked");
toggleAttribute( toggleAttribute(
this, this,
"expanded", "modal",
this.narrow || this.hass.dockedSidebar !== "auto" this._sidebarNarrow || this._externalSidebar
); );
} }
@ -165,20 +167,20 @@ export class HomeAssistantMain extends LitElement {
/* remove the grey tap highlights in iOS on the fullscreen touch targets */ /* remove the grey tap highlights in iOS on the fullscreen touch targets */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
--mdc-drawer-width: 56px; --mdc-drawer-width: 56px;
--mdc-top-app-bar-width: calc(100% - var(--mdc-drawer-width));
} }
:host([expanded]) { :host([expanded]) {
--mdc-drawer-width: calc(256px + env(safe-area-inset-left)); --mdc-drawer-width: calc(256px + env(safe-area-inset-left));
} }
:host([modal]) {
--mdc-drawer-width: unset;
--mdc-top-app-bar-width: unset;
}
partial-panel-resolver, partial-panel-resolver,
ha-sidebar { ha-sidebar {
/* allow a light tap highlight on the actual interface elements */ /* allow a light tap highlight on the actual interface elements */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1); -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
} }
@media (min-width: 870px) {
partial-panel-resolver {
--mdc-top-app-bar-width: calc(100% - var(--mdc-drawer-width));
}
}
`; `;
} }
} }

View File

@ -511,7 +511,7 @@ export class HaAutomationTrace extends LitElement {
justify-content: center; justify-content: center;
font-size: 20px; font-size: 20px;
height: var(--header-height); height: var(--header-height);
padding: 0 16px; padding: 4px;
background-color: var(--primary-background-color); background-color: var(--primary-background-color);
font-weight: 400; font-weight: 400;
color: var(--app-header-text-color, white); color: var(--app-header-text-color, white);

View File

@ -376,7 +376,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
); );
const filterMenu = html` const filterMenu = html`
<div slot=${ifDefined(this.narrow ? "toolbar-icon" : "suffix")}> <div slot=${ifDefined(this.narrow ? "toolbar-icon" : undefined)}>
<div class="menu-badge-container"> <div class="menu-badge-container">
${!this._showDisabled && this.narrow && disabledCount ${!this._showDisabled && this.narrow && disabledCount
? html`<span class="badge">${disabledCount}</span>` ? html`<span class="badge">${disabledCount}</span>`
@ -455,24 +455,25 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
)} )}
> >
${!this._showDisabled && disabledCount ${!this._showDisabled && disabledCount
? html`<div ? html`<div class="filters" slot="suffix">
class="active-filters" <div
slot="suffix" class="active-filters"
@click=${this._preventDefault} @click=${this._preventDefault}
> >
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.integrations.disable.disabled_integrations", "ui.panel.config.integrations.disable.disabled_integrations",
{ number: disabledCount } { number: disabledCount }
)}
<mwc-button
@click=${this._toggleShowDisabled}
.label=${this.hass.localize(
"ui.panel.config.integrations.disable.show"
)} )}
></mwc-button> <mwc-button
@click=${this._toggleShowDisabled}
.label=${this.hass.localize(
"ui.panel.config.integrations.disable.show"
)}
></mwc-button>
</div>
${filterMenu}
</div>` </div>`
: ""} : ""}
${filterMenu}
</search-input> </search-input>
</div> </div>
`} `}
@ -845,7 +846,6 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
.container > * { .container > * {
max-width: 500px; max-width: 500px;
} }
.empty-message { .empty-message {
margin: auto; margin: auto;
text-align: center; text-align: center;
@ -884,6 +884,15 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
right: 0; right: 0;
left: 0; left: 0;
} }
.filters {
--mdc-text-field-fill-color: var(--input-fill-color);
--mdc-text-field-idle-line-color: var(--input-idle-line-color);
--mdc-shape-small: 4px;
--text-field-overflow: initial;
display: flex;
justify-content: flex-end;
color: var(--primary-text-color);
}
.active-filters { .active-filters {
color: var(--primary-text-color); color: var(--primary-text-color);
position: relative; position: relative;

View File

@ -108,10 +108,15 @@ class PanelDeveloperTools extends LitElement {
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 20px; font-size: 20px;
padding: 0 16px; padding: 8px 12px;
font-weight: 400; font-weight: 400;
box-sizing: border-box; box-sizing: border-box;
} }
@media (max-width: 599px) {
.toolbar {
padding: 4px;
}
}
.main-title { .main-title {
margin: 0 0 0 24px; margin: 0 0 0 24px;
line-height: 20px; line-height: 20px;

View File

@ -157,6 +157,9 @@ export class HuiEnergyGasGraphCard
const options: ChartOptions = { const options: ChartOptions = {
parsing: false, parsing: false,
animation: false, animation: false,
interaction: {
mode: "x",
},
scales: { scales: {
x: { x: {
type: "time", type: "time",
@ -171,9 +174,6 @@ export class HuiEnergyGasGraphCard
maxRotation: 0, maxRotation: 0,
sampleSize: 5, sampleSize: 5,
autoSkipPadding: 20, autoSkipPadding: 20,
major: {
enabled: true,
},
font: (context) => font: (context) =>
context.tick && context.tick.major context.tick && context.tick.major
? ({ weight: "bold" } as any) ? ({ weight: "bold" } as any)
@ -213,7 +213,7 @@ export class HuiEnergyGasGraphCard
}, },
plugins: { plugins: {
tooltip: { tooltip: {
mode: "nearest", position: "nearest",
callbacks: { callbacks: {
title: (datasets) => { title: (datasets) => {
if (dayDifference > 0) { if (dayDifference > 0) {
@ -244,13 +244,10 @@ export class HuiEnergyGasGraphCard
}, },
}, },
}, },
hover: {
mode: "nearest",
},
elements: { elements: {
bar: { borderWidth: 1.5, borderRadius: 4 }, bar: { borderWidth: 1.5, borderRadius: 4 },
point: { point: {
hitRadius: 5, hitRadius: 50,
}, },
}, },
// @ts-expect-error // @ts-expect-error

View File

@ -154,6 +154,9 @@ export class HuiEnergySolarGraphCard
const options: ChartOptions = { const options: ChartOptions = {
parsing: false, parsing: false,
animation: false, animation: false,
interaction: {
mode: "x",
},
scales: { scales: {
x: { x: {
type: "time", type: "time",
@ -168,9 +171,6 @@ export class HuiEnergySolarGraphCard
maxRotation: 0, maxRotation: 0,
sampleSize: 5, sampleSize: 5,
autoSkipPadding: 20, autoSkipPadding: 20,
major: {
enabled: true,
},
font: (context) => font: (context) =>
context.tick && context.tick.major context.tick && context.tick.major
? ({ weight: "bold" } as any) ? ({ weight: "bold" } as any)
@ -209,7 +209,7 @@ export class HuiEnergySolarGraphCard
}, },
plugins: { plugins: {
tooltip: { tooltip: {
mode: "nearest", position: "nearest",
callbacks: { callbacks: {
title: (datasets) => { title: (datasets) => {
if (dayDifference > 0) { if (dayDifference > 0) {
@ -240,9 +240,6 @@ export class HuiEnergySolarGraphCard
}, },
}, },
}, },
hover: {
mode: "nearest",
},
elements: { elements: {
line: { line: {
tension: 0.3, tension: 0.3,

View File

@ -148,6 +148,9 @@ export class HuiEnergyUsageGraphCard
const options: ChartOptions = { const options: ChartOptions = {
parsing: false, parsing: false,
animation: false, animation: false,
interaction: {
mode: "x",
},
scales: { scales: {
x: { x: {
type: "time", type: "time",
@ -162,9 +165,6 @@ export class HuiEnergyUsageGraphCard
maxRotation: 0, maxRotation: 0,
sampleSize: 5, sampleSize: 5,
autoSkipPadding: 20, autoSkipPadding: 20,
major: {
enabled: true,
},
font: (context) => font: (context) =>
context.tick && context.tick.major context.tick && context.tick.major
? ({ weight: "bold" } as any) ? ({ weight: "bold" } as any)
@ -204,8 +204,6 @@ export class HuiEnergyUsageGraphCard
}, },
plugins: { plugins: {
tooltip: { tooltip: {
mode: "x",
intersect: true,
position: "nearest", position: "nearest",
filter: (val) => val.formattedValue !== "0", filter: (val) => val.formattedValue !== "0",
callbacks: { callbacks: {
@ -265,13 +263,10 @@ export class HuiEnergyUsageGraphCard
}, },
}, },
}, },
hover: {
mode: "nearest",
},
elements: { elements: {
bar: { borderWidth: 1.5, borderRadius: 4 }, bar: { borderWidth: 1.5, borderRadius: 4 },
point: { point: {
hitRadius: 5, hitRadius: 50,
}, },
}, },
// @ts-expect-error // @ts-expect-error

View File

@ -157,6 +157,9 @@ export class HuiEnergyWaterGraphCard
const options: ChartOptions = { const options: ChartOptions = {
parsing: false, parsing: false,
animation: false, animation: false,
interaction: {
mode: "x",
},
scales: { scales: {
x: { x: {
type: "time", type: "time",
@ -171,9 +174,6 @@ export class HuiEnergyWaterGraphCard
maxRotation: 0, maxRotation: 0,
sampleSize: 5, sampleSize: 5,
autoSkipPadding: 20, autoSkipPadding: 20,
major: {
enabled: true,
},
font: (context) => font: (context) =>
context.tick && context.tick.major context.tick && context.tick.major
? ({ weight: "bold" } as any) ? ({ weight: "bold" } as any)
@ -213,7 +213,7 @@ export class HuiEnergyWaterGraphCard
}, },
plugins: { plugins: {
tooltip: { tooltip: {
mode: "nearest", position: "nearest",
callbacks: { callbacks: {
title: (datasets) => { title: (datasets) => {
if (dayDifference > 0) { if (dayDifference > 0) {
@ -244,13 +244,10 @@ export class HuiEnergyWaterGraphCard
}, },
}, },
}, },
hover: {
mode: "nearest",
},
elements: { elements: {
bar: { borderWidth: 1.5, borderRadius: 4 }, bar: { borderWidth: 1.5, borderRadius: 4 },
point: { point: {
hitRadius: 5, hitRadius: 50,
}, },
}, },
// @ts-expect-error // @ts-expect-error

View File

@ -36,9 +36,12 @@ import "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-image"; import "../../../components/tile/ha-tile-image";
import "../../../components/tile/ha-tile-info"; import "../../../components/tile/ha-tile-info";
import { cameraUrlWithWidthHeight } from "../../../data/camera"; import { cameraUrlWithWidthHeight } from "../../../data/camera";
import { CoverEntity } from "../../../data/cover"; import {
import { isUnavailableState, ON } from "../../../data/entity"; computeCoverPositionStateDisplay,
import { FanEntity } from "../../../data/fan"; CoverEntity,
} from "../../../data/cover";
import { isUnavailableState } from "../../../data/entity";
import { computeFanSpeedStateDisplay, FanEntity } from "../../../data/fan";
import { LightEntity } from "../../../data/light"; import { LightEntity } from "../../../data/light";
import { ActionHandlerEvent } from "../../../data/lovelace"; import { ActionHandlerEvent } from "../../../data/lovelace";
import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor"; import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor";
@ -202,7 +205,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
`; `;
} }
if (domain === "light" && stateObj.state === ON) { if (domain === "light" && stateActive(stateObj)) {
const brightness = (stateObj as LightEntity).attributes.brightness; const brightness = (stateObj as LightEntity).attributes.brightness;
if (brightness) { if (brightness) {
return `${Math.round((brightness * 100) / 255)}${blankBeforePercent( return `${Math.round((brightness * 100) / 255)}${blankBeforePercent(
@ -211,10 +214,13 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
} }
} }
if (domain === "fan" && stateObj.state === ON) { if (domain === "fan" && stateActive(stateObj)) {
const speed = (stateObj as FanEntity).attributes.percentage; const speedStateDisplay = computeFanSpeedStateDisplay(
if (speed) { stateObj as FanEntity,
return `${Math.round(speed)}${blankBeforePercent(this.hass!.locale)}%`; this.hass!.locale
);
if (speedStateDisplay) {
return speedStateDisplay;
} }
} }
@ -225,15 +231,14 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
this.hass!.entities this.hass!.entities
); );
if ( if (domain === "cover" && stateActive(stateObj)) {
domain === "cover" && const positionStateDisplay = computeCoverPositionStateDisplay(
["open", "opening", "closing"].includes(stateObj.state) stateObj as CoverEntity,
) { this.hass!.locale
const position = (stateObj as CoverEntity).attributes.current_position; );
if (position && position !== 100) {
return `${stateDisplay} - ${Math.round(position)}${blankBeforePercent( if (positionStateDisplay) {
this.hass!.locale return `${stateDisplay}${positionStateDisplay}`;
)}%`;
} }
} }
return stateDisplay; return stateDisplay;

View File

@ -63,7 +63,7 @@ class ActionHandler extends HTMLElement implements ActionHandler {
public connectedCallback() { public connectedCallback() {
Object.assign(this.style, { Object.assign(this.style, {
position: "absolute", position: "fixed",
width: isTouch ? "100px" : "50px", width: isTouch ? "100px" : "50px",
height: isTouch ? "100px" : "50px", height: isTouch ? "100px" : "50px",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
@ -147,11 +147,11 @@ class ActionHandler extends HTMLElement implements ActionHandler {
let x; let x;
let y; let y;
if ((ev as TouchEvent).touches) { if ((ev as TouchEvent).touches) {
x = (ev as TouchEvent).touches[0].pageX; x = (ev as TouchEvent).touches[0].clientX;
y = (ev as TouchEvent).touches[0].pageY; y = (ev as TouchEvent).touches[0].clientY;
} else { } else {
x = (ev as MouseEvent).pageX; x = (ev as MouseEvent).clientX;
y = (ev as MouseEvent).pageY; y = (ev as MouseEvent).clientY;
} }
if (options.hasHold) { if (options.hasHold) {

View File

@ -164,7 +164,7 @@ export class HuiCreateDialogCard
ha-dialog { ha-dialog {
--mdc-dialog-max-width: 845px; --mdc-dialog-max-width: 845px;
--dialog-content-padding: 2px 24px 20px 24px; --dialog-content-padding: 2px 24px 20px 24px;
--dialog-z-index: 5; --dialog-z-index: 6;
} }
ha-dialog.table { ha-dialog.table {

View File

@ -394,7 +394,7 @@ export class HuiDialogEditCard
ha-dialog { ha-dialog {
--mdc-dialog-max-width: 845px; --mdc-dialog-max-width: 845px;
--dialog-z-index: 5; --dialog-z-index: 6;
} }
@media all and (min-width: 451px) and (min-height: 501px) { @media all and (min-width: 451px) and (min-height: 501px) {

View File

@ -143,7 +143,7 @@ export class HuiDialogSuggestCard extends LitElement {
} }
ha-dialog { ha-dialog {
max-width: 845px; max-width: 845px;
--dialog-z-index: 5; --dialog-z-index: 6;
} }
.hidden { .hidden {
display: none; display: none;

View File

@ -145,7 +145,7 @@ export class HuiCreateDialogHeaderFooter
ha-dialog { ha-dialog {
--mdc-dialog-max-width: 550px; --mdc-dialog-max-width: 550px;
--dialog-content-padding: 2px 24px 20px 24px; --dialog-content-padding: 2px 24px 20px 24px;
--dialog-z-index: 5; --dialog-z-index: 6;
} }
.elements { .elements {

View File

@ -26,7 +26,13 @@ import {
PropertyValues, PropertyValues,
TemplateResult, TemplateResult,
} from "lit"; } from "lit";
import { customElement, property, query, state } from "lit/decorators"; import {
customElement,
eventOptions,
property,
query,
state,
} from "lit/decorators";
import { classMap } from "lit/directives/class-map"; import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined"; import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
@ -116,9 +122,9 @@ class HUIRoot extends LitElement {
return html` return html`
<div <div
class=" ${classMap({ class=${classMap({
"edit-mode": this._editMode, "edit-mode": this._editMode,
})}" })}
> >
<div class="header"> <div class="header">
<div class="toolbar"> <div class="toolbar">
@ -547,11 +553,20 @@ class HUIRoot extends LitElement {
` `
: ""} : ""}
</div> </div>
<div id="view" @ll-rebuild=${this._debouncedConfigChanged}></div> <div
id="view"
@ll-rebuild=${this._debouncedConfigChanged}
@scroll=${this._viewScrolled}
></div>
</div> </div>
`; `;
} }
@eventOptions({ passive: true })
private _viewScrolled(ev) {
this.toggleAttribute("scrolled", ev.currentTarget.scrollTop !== 0);
}
private _isVisible = (view: LovelaceViewConfig) => private _isVisible = (view: LovelaceViewConfig) =>
Boolean( Boolean(
this._editMode || this._editMode ||
@ -947,6 +962,10 @@ class HUIRoot extends LitElement {
top: 0; top: 0;
width: var(--mdc-top-app-bar-width, 100%); width: var(--mdc-top-app-bar-width, 100%);
z-index: 2; z-index: 2;
transition: box-shadow 0.3s ease-out;
}
:host([scrolled]) .header {
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75);
} }
.edit-mode .header { .edit-mode .header {
background-color: var(--app-header-edit-background-color, #455a64); background-color: var(--app-header-edit-background-color, #455a64);
@ -957,10 +976,15 @@ class HUIRoot extends LitElement {
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 20px; font-size: 20px;
padding: 0 16px; padding: 0px 12px;
font-weight: 400; font-weight: 400;
box-sizing: border-box; box-sizing: border-box;
} }
@media (max-width: 599px) {
.toolbar {
padding: 0 4px;
}
}
.main-title { .main-title {
margin: 0 0 0 24px; margin: 0 0 0 24px;
line-height: 20px; line-height: 20px;
@ -1025,14 +1049,10 @@ class HUIRoot extends LitElement {
100vh - var(--header-height) - env(safe-area-inset-top) - 100vh - var(--header-height) - env(safe-area-inset-top) -
env(safe-area-inset-bottom) env(safe-area-inset-bottom)
); );
/** background: var(
* Since we only set min-height, if child nodes need percentage --lovelace-background,
* heights they must use absolute positioning so we need relative var(--primary-background-color)
* positioning here. );
*
* https://www.w3.org/TR/CSS2/visudet.html#the-height-property
*/
position: relative;
display: flex; display: flex;
overflow: auto; overflow: auto;
} }
@ -1064,12 +1084,6 @@ class HUIRoot extends LitElement {
.menu-link { .menu-link {
text-decoration: none; text-decoration: none;
} }
hui-view {
background: var(
--lovelace-background,
var(--primary-background-color)
);
}
.exit-edit-mode { .exit-edit-mode {
--mdc-theme-primary: var(--app-header-edit-text-color, #fff); --mdc-theme-primary: var(--app-header-edit-text-color, #fff);
--mdc-button-outline-color: var(--app-header-edit-text-color, #fff); --mdc-button-outline-color: var(--app-header-edit-text-color, #fff);

View File

@ -1,7 +1,8 @@
const { createAppConfig } = require("../build-scripts/webpack.js"); import webpack from "../build-scripts/webpack.cjs";
module.exports = createAppConfig({ export default webpack.createAppConfig({
isProdBuild: false, isProdBuild: false,
latestBuild: true, latestBuild: true,
isStatsBuild: false, isStatsBuild: false,
isTestBuild: true,
}); });

View File

@ -1,20 +1,26 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es2017", // Language Options
"module": "esnext", "target": "ES2017",
"lib": ["ES2017", "DOM", "DOM.Iterable", "WebWorker"],
"experimentalDecorators": true,
// Modules
"module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"lib": ["es2017", "dom", "dom.iterable", "WebWorker"], "resolveJsonModule": true,
// Babel handles transpiling and no need for declaration files
"noEmit": true, "noEmit": true,
// Type checking options
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"strict": true, "strict": true,
"noImplicitAny": false, "noImplicitAny": false,
// Do not check type declaration files
"skipLibCheck": true, "skipLibCheck": true,
"resolveJsonModule": true, // Interop with CommonJS and other tools
"experimentalDecorators": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"plugins": [ "plugins": [
{ {
"name": "ts-lit-plugin", "name": "ts-lit-plugin",

View File

@ -1,7 +1,6 @@
const cors = require("@koa/cors"); import cors from "@koa/cors";
const { rollupAdapter } = require("@web/dev-server-rollup"); import { rollupAdapter } from "@web/dev-server-rollup";
import rollup from "./build-scripts/rollup.cjs";
const rollup = require("./build-scripts/rollup");
const rollupWDSPlugins = rollup const rollupWDSPlugins = rollup
.createAppConfig({ .createAppConfig({
@ -13,7 +12,7 @@ const rollupWDSPlugins = rollup
); );
/** @type import("@web/dev-server/src/config/DevServerConfig.ts") */ /** @type import("@web/dev-server/src/config/DevServerConfig.ts") */
module.exports = { export default {
mimeTypes: { mimeTypes: {
"**/*.ts": "js", "**/*.ts": "js",
"**/*.json": "js", "**/*.json": "js",

28
webpack.config.cjs Normal file
View File

@ -0,0 +1,28 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Needs to remain CommonJS until eslint-import-resolver-webpack supports ES modules
const webpack = require("./build-scripts/webpack.cjs");
const env = require("./build-scripts/env.cjs");
// This file exists because we haven't migrated the stats script yet
const configs = [
webpack.createAppConfig({
isProdBuild: env.isProdBuild(),
isStatsBuild: env.isStatsBuild(),
isTestBuild: env.isTestBuild(),
latestBuild: true,
}),
];
if (env.isProdBuild() && !env.isStatsBuild()) {
configs.push(
webpack.createAppConfig({
isProdBuild: env.isProdBuild(),
isStatsBuild: env.isStatsBuild(),
isTestBuild: env.isTestBuild(),
latestBuild: false,
})
);
}
module.exports = configs;

View File

@ -1,33 +0,0 @@
/* eslint-disable import/extensions */
/* eslint-disable @typescript-eslint/no-var-requires */
const { createAppConfig } = require("./build-scripts/webpack.js");
const {
isProdBuild,
isStatsBuild,
isTestBuild,
} = require("./build-scripts/env.js");
// This file exists because we haven't migrated the stats script yet
const configs = [
createAppConfig({
isProdBuild: isProdBuild(),
isStatsBuild: isStatsBuild(),
isTestBuild: isTestBuild(),
latestBuild: true,
}),
];
// const configs = [createConfig(isProdBuild, /* latestBuild */ true)];
if (isProdBuild && !isStatsBuild) {
configs.push(
createAppConfig({
isProdBuild: isProdBuild(),
isStatsBuild: isStatsBuild(),
isTestBuild: isTestBuild(),
latestBuild: false,
})
);
}
module.exports = configs;

View File

@ -3897,14 +3897,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sinonjs/samsam@npm:^7.0.1": "@sinonjs/samsam@npm:^8.0.0":
version: 7.0.1 version: 8.0.0
resolution: "@sinonjs/samsam@npm:7.0.1" resolution: "@sinonjs/samsam@npm:8.0.0"
dependencies: dependencies:
"@sinonjs/commons": ^2.0.0 "@sinonjs/commons": ^2.0.0
lodash.get: ^4.4.2 lodash.get: ^4.4.2
type-detect: ^4.0.8 type-detect: ^4.0.8
checksum: 291efb158d54c67dee23ddabcb28873d22063449b692aaa3b2a4f1826d2f79d38695574063c92e9c17573cc805cd6acbf0ab0c66c9f3aed7afd0f12a2b905615 checksum: 95e40d0bb9f7288e27c379bee1b03c3dc51e7e78b9d5ea6aef66a690da7e81efc4715145b561b449cefc5361a171791e3ce30fb1a46ab247d4c0766024c60a60
languageName: node languageName: node
linkType: hard linkType: hard
@ -9571,7 +9571,6 @@ __metadata:
qr-scanner: 1.4.2 qr-scanner: 1.4.2
qrcode: 1.5.1 qrcode: 1.5.1
regenerator-runtime: 0.13.11 regenerator-runtime: 0.13.11
require-dir: 1.2.0
resize-observer-polyfill: 1.5.1 resize-observer-polyfill: 1.5.1
roboto-fontface: 0.10.0 roboto-fontface: 0.10.0
rollup: 2.79.1 rollup: 2.79.1
@ -9580,7 +9579,7 @@ __metadata:
rollup-plugin-visualizer: 5.9.0 rollup-plugin-visualizer: 5.9.0
rrule: 2.7.2 rrule: 2.7.2
serve-handler: 6.1.5 serve-handler: 6.1.5
sinon: 15.0.2 sinon: 15.0.3
sortablejs: 1.15.0 sortablejs: 1.15.0
source-map-url: 0.4.1 source-map-url: 0.4.1
superstruct: 1.0.3 superstruct: 1.0.3
@ -13443,13 +13442,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"require-dir@npm:1.2.0":
version: 1.2.0
resolution: "require-dir@npm:1.2.0"
checksum: 8bbc4757d7e3fae0799e24cb363f165a89e0cc83172de9d5fd95f8e75cf2368764199e5fd557434d6318ab1f271415cc9d3ef190076393e6e993a7b1add8ef27
languageName: node
linkType: hard
"require-directory@npm:^2.1.1": "require-directory@npm:^2.1.1":
version: 2.1.1 version: 2.1.1
resolution: "require-directory@npm:2.1.1" resolution: "require-directory@npm:2.1.1"
@ -14052,17 +14044,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"sinon@npm:15.0.2": "sinon@npm:15.0.3":
version: 15.0.2 version: 15.0.3
resolution: "sinon@npm:15.0.2" resolution: "sinon@npm:15.0.3"
dependencies: dependencies:
"@sinonjs/commons": ^3.0.0 "@sinonjs/commons": ^3.0.0
"@sinonjs/fake-timers": ^10.0.2 "@sinonjs/fake-timers": ^10.0.2
"@sinonjs/samsam": ^7.0.1 "@sinonjs/samsam": ^8.0.0
diff: ^5.1.0 diff: ^5.1.0
nise: ^5.1.4 nise: ^5.1.4
supports-color: ^7.2.0 supports-color: ^7.2.0
checksum: 98eb555442db3985d7fe0d90e23f081f3df71adffa0a50b049bcd2abbf5c2d71a43aeaa1e3c02500164cff5233d2f102f777356ebe8bfc257cb7059c1b2778b0 checksum: fb9401e44215c7a7904d2df3032c56369cb4f2fd9c708460e1b980c6032de8e13bd8c4d90039074f9383e5219702a5e0755b7bea94bd4c090b8c1e583f137c3d
languageName: node languageName: node
linkType: hard linkType: hard