Compare commits

..

104 Commits

Author SHA1 Message Date
Bram Kragten
a548d13931 Allow partial open of sidebar 2023-04-01 18:46:52 +02:00
Bram Kragten
ddfe02eb70 Bumped version to 20230401.0 2023-04-01 18:20:48 +02:00
Bram Kragten
acaaf25500 Use ha-drawer instead of mwc-drawer (#16013) 2023-04-01 16:18:52 +00:00
renovate[bot]
c6c3e63101 Update dependency @web/dev-server to v0.1.37 (#16008) 2023-04-01 10:31:47 -04:00
renovate[bot]
e0fe4631f9 Update dependency eslint to v8.37.0 (#16007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-01 01:56:46 -04:00
Paulus Schoutsen
232f70d44c Allow having conversations (#15961)
* Allow having conversations

* Add timeout to run-start data

* willUpdate
2023-03-31 15:44:32 -04:00
Bram Kragten
273904a6eb Add support for supported_features for entity selector (#16003) 2023-03-31 15:07:41 -04:00
Steve Repsher
91caffc4e1 Improve bundle chunk hashes and names (#15991) 2023-03-31 12:49:25 -04:00
Bram Kragten
abcb904def Bumped version to 20230331.0 2023-03-31 16:37:33 +02:00
Bram Kragten
36c5d70597 Add sidebar actions to external bus (#15999) 2023-03-31 16:36:11 +02:00
Paul Bottein
b0b7998757 Fix for long translation in alarm more info (#16000) 2023-03-31 14:24:03 +00:00
Paul Bottein
33ec1e15a9 Fix labels on new more info (#15983) 2023-03-31 15:57:35 +02:00
Paul Bottein
d97ddcd31a Catch alarm control panel errors (#15998) 2023-03-31 15:51:44 +02:00
Paul Bottein
73c286a493 Fix ha header bar height (#15996)
* Fix ha header bar height in more info

* Fix ha header bar height in more places
2023-03-31 15:44:22 +02:00
Franck Nijhof
3e954eef02 Extend get_states (#15985) 2023-03-31 15:29:24 +02:00
Paul Bottein
a94b211d3e Fix ha-settings-row overflow (#15993) 2023-03-31 13:02:36 +02:00
renovate[bot]
1293e5f61f Update typescript-eslint monorepo to v5.57.0 (#15986)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-30 15:35:02 -04:00
Bram Kragten
287b0b9235 Bumped version to 20230330.0 2023-03-30 16:58:32 +02:00
Bram Kragten
3d6743ae3e Align header paddings (#15981) 2023-03-30 16:57:25 +02:00
Bram Kragten
5193f2c6a4 Fix header when sidebar always hidden (#15980) 2023-03-30 16:46:31 +02:00
Paul Bottein
e6772e8b89 Fix fan more info state display (#15979) 2023-03-30 16:20:30 +02:00
Bram Kragten
dcac853b71 Improve graph tooltips (#15887
* Improve graph tooltips

* Use xy for state charts

* intersect, bigger hitRadius

* improve energy

* fix position tooltips
2023-03-30 16:12:26 +02:00
Bram Kragten
0df096d68b Fix overflow, change position of action-handler (#15978) 2023-03-30 16:10:54 +02:00
Bram Kragten
ef10cc77f7 Fix lovelace background, tweak headers (#15977) 2023-03-30 16:10:43 +02:00
Paul Bottein
e52b2c49a6 Fix mouse event for remove icon in ha file upload (#15976) 2023-03-30 11:59:50 +00:00
Paul Bottein
78cc75c57c Fix cover more info state display (#15974) 2023-03-30 09:55:13 +00:00
Bram Kragten
2b38a1ce33 Fix dialogs under sidebar, headers (#15973) 2023-03-30 11:46:34 +02:00
Steve Repsher
1f1898fa46 Make module types explicit and convert some to ESM (#15964) 2023-03-30 11:23:43 +02:00
renovate[bot]
fcc95825e3 Update dependency sinon to v15.0.3 (#15972) 2023-03-29 21:03:33 -04:00
Bram Kragten
bdfdab439a Merge branch 'master' into dev 2023-03-29 17:54:53 +02:00
Bram Kragten
8c59537032 Bumped version to 20230329.0 2023-03-29 17:48:14 +02:00
Bram Kragten
f5a4affdec Use mwc-drawer (#10335
* Use mwc-drawer

* Update home-assistant-main.ts

* Implement top-app-bar

* Update home-assistant-main.ts

* update hui-root

* WIP

tabs don't work yet

* migrate most panels

* fixed

* notifications-drawer

* developer tools

* lovelace

* Update hui-root.ts

* Update hui-root.ts

* Update notification-drawer.ts

* fix dev tools

* Update ha-panel-developer-tools.ts
2023-03-29 17:46:34 +02:00
Bram Kragten
f19fdeacba bump @lit-labs/context, fix bug in button card + optimise (#15968) 2023-03-29 12:45:52 +00:00
Paul Bottein
e0f7544d2f Alarm mode tile feature (#15967) 2023-03-29 12:27:39 +02:00
Paul Bottein
4d2d7cd125 Use nothing in more lit template (#15966)
* Use nothing in more lit template

* Use nothing in more lit template
2023-03-29 12:20:25 +02:00
Bram Kragten
0f5320c6fb Drop polymer from authorize and onboarding entrypoint (#15760)
* Drop polymer from authorize and onboarding entrypoint

* Update ha-icon.ts

* dedupe
2023-03-29 12:17:42 +02:00
karwosts
4d52913a01 Add missing import for duration selector (#15960) 2023-03-28 20:25:06 -04:00
karwosts
0f97a76428 Fix map card error rendering (#15910) 2023-03-28 16:15:56 +00:00
Paul Bottein
f2cf598f98 Fan speed tile feature (#15958)
* Move fan speed rules outside fan more info

* Add fan speed tile feature

* Improve select style
2023-03-28 17:59:07 +02:00
Franck Nijhof
a6f9482bf6 Improve/extend description of conditions (#15943) 2023-03-28 16:43:00 +02:00
Paul Bottein
48c74c8660 Add more info alarm control panel (#15893)
* Add more info alarm control panel

* Improve buttons sizes

* Add triggered, arming and pending state

* Add keypad

* Improve alarm code dialog

* Fix code condition

* Clean code

* Fix mode selection with code

* Use nothing
2023-03-28 16:31:25 +02:00
Paul Bottein
3a700aebcc Improve padding to avoid input number overflow (#15888) 2023-03-28 14:40:02 +02:00
Paul Bottein
cd6aac85d2 Update oscillating icon (#15948) 2023-03-28 13:28:52 +02:00
renovate[bot]
77b227a7d1 Update vaadinWebComponents monorepo to v23.3.9 (#15951) 2023-03-27 21:11:59 -04:00
Stefan Agner
b785fedef2 Add-on store: Use more formal wording (#15952)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2023-03-27 22:18:18 +02:00
renovate[bot]
66a202be7e Update dependency @lezer/highlight to v1.1.4 (#15949) 2023-03-27 09:31:45 -04:00
renovate[bot]
0ad02013ba Update dependency prettier to v2.8.7 (#15950) 2023-03-27 09:30:40 -04:00
Paul Bottein
1b2eaedba0 Don't wait for slider release to update color temp (#15914) 2023-03-27 10:34:05 +02:00
Paul Bottein
8ea350a488 Add cover new more info (#15694)
* Add cover new  more info

* Improve tilt cover control

* Improve controls

* Better handle group

* Refactor toggle component

* Use deep purple for cover and adjust deep purple color

* Update purple color

* Feedbacks

* Change color

* Improve tilt backgroud constrast
2023-03-27 10:11:28 +02:00
dependabot[bot]
8ff56bd8f5 Bump actions/stale from 7.0.0 to 8.0.0 (#15945)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 09:41:03 +02:00
dependabot[bot]
dd7ec07f29 Bump actions/checkout from 3.4.0 to 3.5.0 (#15946)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 09:29:50 +02:00
Paulus Schoutsen
520f489830 Pipeline updates (#15926)
* Allow using TTS

* Allow streaming audio from frontens to STT

* Improve stop recording

* Even better stop
2023-03-26 22:42:08 -04:00
renovate[bot]
395358b192 Update dependency vis-network to v9.1.6 (#15944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-26 21:42:10 -04:00
Raman Gupta
a19ff5aef5 Add milliseconds support for duration sensors (#15895) 2023-03-26 23:52:18 +02:00
renovate[bot]
34f8b48fbe Update dependency glob to v9.3.2 (#15938) 2023-03-25 19:18:59 +00:00
renovate[bot]
01f8b4e1c4 Update dependency marked to v4.3.0 (#15935) 2023-03-25 19:02:09 +00:00
renovate[bot]
9e1cdf8215 Update dependency vis-data to v7.1.6 (#15929) 2023-03-25 14:41:15 -04:00
renovate[bot]
551127b844 Update dependency vis-network to v9.1.5 (#15925)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 14:34:05 -04:00
renovate[bot]
afe42629b2 Update dependency systemjs to v6.14.1 (#15924)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 14:32:17 -04:00
renovate[bot]
848d12e6fe Update dependency intl-messageformat to v10.3.3 (#15920) 2023-03-24 08:38:44 -04:00
renovate[bot]
65bd373af4 Update dependency glob to v9.3.1 (#15919) 2023-03-24 08:37:01 -04:00
renovate[bot]
91c099632d Update dependency prettier to v2.8.6 (#15921) 2023-03-24 08:35:01 -04:00
Sven Serlier
9053bc7b78 Update URLs (#15915)
* Update URL

* Update URL
2023-03-24 11:27:45 +01:00
renovate[bot]
9c4b0259a8 Update typescript-eslint monorepo to v5.56.0 (#15917) 2023-03-23 19:14:28 -04:00
renovate[bot]
7930f3879d Update dependency eslint-config-prettier to v8.8.0 (#15916) 2023-03-23 19:09:19 -04:00
Paulus Schoutsen
d9dbb69e62 Update voice debug for new API (#15913)
* Update voice debug for new API

* Update imports

* Remove wrong key

* Some HTML formatting
2023-03-23 14:44:23 -04:00
Bram Kragten
74cfccaac7 Add context providers and transform decorator (#15902) 2023-03-23 18:31:01 +01:00
Bram Kragten
4ba7e5cf0f Fix css minifying (#15912) 2023-03-23 18:28:23 +01:00
renovate[bot]
fc76d8f1cf Update dependency @polymer/polymer to v3.5.1 (#15720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 16:18:31 +00:00
renovate[bot]
3eb07e9bc3 Update dependency fs-extra to v11.1.1 (#15911)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 16:58:04 +01:00
karwosts
4e6ed61e2b Add default placeholders for various number fields in cards (#15903) 2023-03-23 15:15:38 +01:00
renovate[bot]
ca6d1544d1 Update dependency @mdi/js to v7.2.96 (#15904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 13:00:01 +00:00
renovate[bot]
81e9bc894b Update CodeMirror (#15908)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 12:55:38 +00:00
renovate[bot]
173d13ae66 Update dependency @mdi/svg to v7.2.96 (#15905)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 08:42:32 -04:00
renovate[bot]
886ae791bc Update dependency prettier to v2.8.5 (#15907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 08:38:30 -04:00
renovate[bot]
50b7e72688 Lock file maintenance (#15865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-03-22 17:24:36 +00:00
karwosts
d07ae1cf48 Fix statistics graph days_to_show can't be erased (#15892) 2023-03-22 17:56:04 +01:00
karwosts
da2de3c7d2 Fix problems in map card when hours_to_show is 0 (#15900) 2023-03-22 17:55:30 +01:00
karwosts
7c62b08fdd Allow map card to render passive zones (#15901) 2023-03-22 17:51:47 +01:00
renovate[bot]
4f5fca7c60 Update dependency intl-messageformat to v10.3.2 (#15899)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-22 10:03:42 -04:00
Paul Bottein
45c153d374 Add fan new more info (#15843)
* Add more info fan

* Change icon

* Use backend translations

* Fix computeAttributeValueDisplay

* Clean code

* Clean code

* Fix some styles

* Improve ha-select rounded style

* Use button instead of select

* Show fan speed percentage
2023-03-22 13:20:14 +01:00
Franck Nijhof
cd2996734c Compute (attribute) states in automation trigger descriptions (#15848) 2023-03-22 11:44:43 +01:00
Steve Repsher
4abc2a65cb Migrate to html-minifier-terser and improve some minification (#15864) 2023-03-22 11:42:16 +01:00
karwosts
89decd2f31 Force app-datepicker calendar to render in ltr (#15894) 2023-03-22 11:24:16 +01:00
renovate[bot]
04a16812d3 Update dependency webpack-dev-server to v4.13.1 (#15896) 2023-03-21 19:16:59 -04:00
renovate[bot]
cadbc501e2 Update dependency webpack-dev-server to v4.13.0 (#15891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-20 22:27:15 +00:00
renovate[bot]
0d95d856c1 Update dependency hls.js to v1.3.5 (#15890)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-20 18:11:37 -04:00
Paul Bottein
d272783258 Mock history stream for demo (#15886)
* Mock history stream for demo

* Fix type error
2023-03-20 20:39:01 +01:00
Paul Bottein
65d3af6fd6 Add white mode to more info light (#15774) 2023-03-20 20:38:48 +01:00
Bram Kragten
24c3ddb96b Allow reset of otbr network, thread panel fixes (#15815) 2023-03-20 20:06:40 +01:00
dependabot[bot]
c9d709152a Bump actions/checkout from 3.3.0 to 3.4.0 (#15883)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 09:07:14 +01:00
Bram Kragten
7b2afa3df9 Bumped version to 20230309.1 2023-03-16 14:41:03 +01:00
Bram Kragten
13a3db4141 Bump style-mod (#15805) 2023-03-16 14:39:42 +01:00
Paul Bottein
a8d7f8a7fe 20230309.0 (#15784) 2023-03-09 16:32:36 +01:00
Bram Kragten
0b3e954752 20230306.0 (#15749) 2023-03-06 12:06:01 +01:00
Paul Bottein
a57609380a 20230302.0 (#15678) 2023-03-02 14:45:40 +01:00
Bram Kragten
db1f81e0ef 20230301.0 (#15657) 2023-03-01 16:36:00 +01:00
Paul Bottein
a8a85a2af6 20230227.0 (#15625) 2023-02-27 21:10:57 +01:00
Bram Kragten
df8f46388f 20230224.0 (#15588) 2023-02-24 21:06:33 +01:00
Bram Kragten
dd6437376d 20230223.0 (#15575) 2023-02-23 19:01:26 +01:00
Bram Kragten
971d2ff1c2 20230222.0 (#15551)Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Steve Repsher <steverep@users.noreply.github.com> Co-authored-by: Bram Kragten <mail@bramkragten.nl> Co-authored-by: Paul Bottein <paul.bottein@gmail.com> Co-authored-by: Flavien Charlon <Flavien@users.noreply.github.com> Co-authored-by: Raman Gupta <7243222+raman325@users.noreply.github.com> Co-authored-by: karwosts <32912880+karwosts@users.noreply.github.com> Co-authored-by: Erik Montnemery <erik@montnemery.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Yosi Levy <37745463+yosilevy@users.noreply.github.com> Co-authored-by: lunmay <28674102+lunmay@users.noreply.github.com> Co-authored-by: Jc2k <john.carr@unrouted.co.uk> Co-authored-by: chiahsing <chiahsing@gmail.com> Co-authored-by: Paulus Schoutsen <balloob@gmail.com> Fix a coloring issue with climate states (#15325) resolver-webpack from 0.13.1 to 0.13.2 (#15355) resolver-webpack](https://github.com/import-js/eslint-plugin-import) from 0.13.1 to 0.13.2. fix some errors (#15334) Fix stats data being fetched for all entities when there are no energy/water stat ids (#15428) Fix custom card documentation url (#15439) fixes (#15446) fix dedupe precommit (#15399) Fix typo from restart dialog (whitch -> which) (#15458) Fix typo in water consumption description (#15464) Fix initial scroll inside more info dialog (#15473) Fix alert padding inside more info dialog (#15477) Fix area name in target picker (#15511) fix history crash) (#15509) Fix promise constructors with returns (#15486) fixes feb23 (#15487) Fix errors in duration data processing in Automation UI Editor (#15422) Fix map sizing in grids and h-stacks (#15290) Fix a typo: Add OpenTread Border Router (#15528) Fix tile card typings (#15529) fix more info history tooltips (#15533) Fix double defined cloud-account (#15537) Fix more info control assumed state color (#15548) Fix a bug in cast launcher that hassURL and path are incorrectly passed (#15546) 2023-02-22 18:16:25 +01:00
Bram Kragten
e6de8ec94d 20230202.0 (#15323) 2023-02-02 20:45:17 +01:00
Bram Kragten
0e06267055 20230201.0 (#15307) 2023-02-01 17:17:12 +01:00
Bram Kragten
63a35c9d68 20230130.0 (#15278) 2023-01-30 22:03:34 +01:00
259 changed files with 8424 additions and 4598 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

@@ -22,7 +22,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
with: with:
ref: dev ref: dev
@@ -58,7 +58,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
with: with:
ref: master ref: master

View File

@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Node ${{ env.NODE_VERSION }} - name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:
@@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Node ${{ env.NODE_VERSION }} - name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:
@@ -66,7 +66,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Node ${{ env.NODE_VERSION }} - name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:
@@ -84,7 +84,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Node ${{ env.NODE_VERSION }} - name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:

View File

@@ -23,7 +23,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
with: with:
# We must fetch at least the immediate parents so that if this is # We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head. # a pull request then we can checkout the head.

View File

@@ -23,7 +23,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
with: with:
ref: dev ref: dev
@@ -59,7 +59,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
with: with:
ref: master ref: master

View File

@@ -17,7 +17,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Node ${{ env.NODE_VERSION }} - name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0

View File

@@ -22,7 +22,7 @@ jobs:
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview') if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
steps: steps:
- name: Check out files from GitHub - name: Check out files from GitHub
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Node ${{ env.NODE_VERSION }} - name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0

View File

@@ -21,7 +21,7 @@ jobs:
contents: write contents: write
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Set up Python ${{ env.PYTHON_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@@ -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

@@ -24,7 +24,7 @@ jobs:
contents: write # Required to upload release assets contents: write # Required to upload release assets
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Verify version - name: Verify version
uses: home-assistant/actions/helpers/verify-version@master uses: home-assistant/actions/helpers/verify-version@master

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 90 days stale policy - name: 90 days stale policy
uses: actions/stale@v7.0.0 uses: actions/stale@v8.0.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90 days-before-stale: 90

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v3.3.0 uses: actions/checkout@v3.5.0
- name: Upload Translations - name: Upload Translations
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
@@ -62,7 +62,7 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
...defineOverlay, ...defineOverlay,
}); });
const htmlMinifierOptions = { module.exports.htmlMinifierOptions = {
caseSensitive: true, caseSensitive: true,
collapseWhitespace: true, collapseWhitespace: true,
conservativeCollapse: true, conservativeCollapse: true,
@@ -70,7 +70,7 @@ const htmlMinifierOptions = {
removeComments: true, removeComments: true,
removeRedundantAttributes: true, removeRedundantAttributes: true,
minifyCSS: { minifyCSS: {
level: 0, compatibility: "*,-properties.zeroUnits",
}, },
}; };
@@ -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"],
@@ -119,7 +119,6 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
"@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-nullish-coalescing-operator",
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }], ["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
"@babel/plugin-proposal-class-static-block",
["@babel/plugin-proposal-private-methods", { loose: true }], ["@babel/plugin-proposal-private-methods", { loose: true }],
["@babel/plugin-proposal-private-property-in-object", { loose: true }], ["@babel/plugin-proposal-private-property-in-object", { loose: true }],
["@babel/plugin-proposal-class-properties", { loose: true }], ["@babel/plugin-proposal-class-properties", { loose: true }],
@@ -136,7 +135,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
"@polymer/polymer/lib/utils/html-tag": ["html"], "@polymer/polymer/lib/utils/html-tag": ["html"],
}, },
strictCSS: true, strictCSS: true,
htmlMinifier: htmlMinifierOptions, htmlMinifier: module.exports.htmlMinifierOptions,
failOnError: true, // we can turn this off in case of false positives failOnError: true, // we can turn this off in case of false positives
}, },
], ],

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

@@ -3,9 +3,10 @@ const gulp = require("gulp");
const fs = require("fs-extra"); 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").minify; 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.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`);
@@ -39,10 +40,12 @@ const renderGalleryTemplate = (pth, data = {}) =>
const minifyHtml = (content) => const minifyHtml = (content) =>
minify(content, { minify(content, {
collapseWhitespace: true, ...htmlMinifierOptions,
minifyJS: true, conservativeCollapse: false,
minifyCSS: true, minifyJS: terserOptions({
removeComments: true, latestBuild: false, // Shared scripts should be ES5
isTestBuild: true, // Don't need source maps
}),
}); });
const PAGES = ["onboarding", "authorize"]; const PAGES = ["onboarding", "authorize"];
@@ -63,7 +66,7 @@ gulp.task("gen-pages-dev", (done) => {
done(); done();
}); });
gulp.task("gen-pages-prod", (done) => { gulp.task("gen-pages-prod", async () => {
const latestManifest = require(path.resolve( const latestManifest = require(path.resolve(
paths.app_output_latest, paths.app_output_latest,
"manifest.json" "manifest.json"
@@ -73,19 +76,23 @@ gulp.task("gen-pages-prod", (done) => {
"manifest.json" "manifest.json"
)); ));
const minifiedHTML = [];
for (const page of PAGES) { for (const page of PAGES) {
const content = renderTemplate(page, { const content = renderTemplate(page, {
latestPageJS: latestManifest[`${page}.js`], latestPageJS: latestManifest[`${page}.js`],
es5PageJS: es5Manifest[`${page}.js`], es5PageJS: es5Manifest[`${page}.js`],
}); });
fs.outputFileSync( minifiedHTML.push(
path.resolve(paths.app_output_root, `${page}.html`), minifyHtml(content).then((minified) =>
minifyHtml(content) fs.outputFileSync(
path.resolve(paths.app_output_root, `${page}.html`),
minified
)
)
); );
} }
done(); await Promise.all(minifiedHTML);
}); });
gulp.task("gen-index-app-dev", (done) => { gulp.task("gen-index-app-dev", (done) => {
@@ -118,7 +125,7 @@ gulp.task("gen-index-app-dev", (done) => {
done(); done();
}); });
gulp.task("gen-index-app-prod", (done) => { gulp.task("gen-index-app-prod", async () => {
const latestManifest = require(path.resolve( const latestManifest = require(path.resolve(
paths.app_output_latest, paths.app_output_latest,
"manifest.json" "manifest.json"
@@ -136,13 +143,15 @@ gulp.task("gen-index-app-prod", (done) => {
es5CoreJS: es5Manifest["core.js"], es5CoreJS: es5Manifest["core.js"],
es5CustomPanelJS: es5Manifest["custom-panel.js"], es5CustomPanelJS: es5Manifest["custom-panel.js"],
}); });
const minified = minifyHtml(content).replace(/#THEMEC/g, "{{ theme_color }}"); const minified = (await minifyHtml(content)).replace(
/#THEMEC/g,
"{{ theme_color }}"
);
fs.outputFileSync( fs.outputFileSync(
path.resolve(paths.app_output_root, "index.html"), path.resolve(paths.app_output_root, "index.html"),
minified minified
); );
done();
}); });
gulp.task("gen-index-cast-dev", (done) => { gulp.task("gen-index-cast-dev", (done) => {
@@ -244,7 +253,7 @@ gulp.task("gen-index-demo-dev", (done) => {
done(); done();
}); });
gulp.task("gen-index-demo-prod", (done) => { gulp.task("gen-index-demo-prod", async () => {
const latestManifest = require(path.resolve( const latestManifest = require(path.resolve(
paths.demo_output_latest, paths.demo_output_latest,
"manifest.json" "manifest.json"
@@ -258,13 +267,12 @@ gulp.task("gen-index-demo-prod", (done) => {
es5DemoJS: es5Manifest["main.js"], es5DemoJS: es5Manifest["main.js"],
}); });
const minified = minifyHtml(content); const minified = await minifyHtml(content);
fs.outputFileSync( fs.outputFileSync(
path.resolve(paths.demo_output_root, "index.html"), path.resolve(paths.demo_output_root, "index.html"),
minified minified
); );
done();
}); });
gulp.task("gen-index-gallery-dev", (done) => { gulp.task("gen-index-gallery-dev", (done) => {
@@ -279,7 +287,7 @@ gulp.task("gen-index-gallery-dev", (done) => {
done(); done();
}); });
gulp.task("gen-index-gallery-prod", (done) => { gulp.task("gen-index-gallery-prod", async () => {
const latestManifest = require(path.resolve( const latestManifest = require(path.resolve(
paths.gallery_output_latest, paths.gallery_output_latest,
"manifest.json" "manifest.json"
@@ -287,13 +295,12 @@ gulp.task("gen-index-gallery-prod", (done) => {
const content = renderGalleryTemplate("index", { const content = renderGalleryTemplate("index", {
latestGalleryJS: latestManifest["entrypoint.js"], latestGalleryJS: latestManifest["entrypoint.js"],
}); });
const minified = minifyHtml(content); const minified = await minifyHtml(content);
fs.outputFileSync( fs.outputFileSync(
path.resolve(paths.gallery_output_root, "index.html"), path.resolve(paths.gallery_output_root, "index.html"),
minified minified
); );
done();
}); });
gulp.task("gen-index-hassio-dev", async () => { gulp.task("gen-index-hassio-dev", async () => {

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;
@@ -152,14 +152,17 @@ const createWebpackConfig = ({
}, },
}, },
output: { output: {
filename: ({ chunk }) => { filename: ({ chunk }) =>
if (!isProdBuild || isStatsBuild || dontHash.has(chunk.name)) { !isProdBuild || isStatsBuild || dontHash.has(chunk.name)
return `${chunk.name}.js`; ? "[name].js"
} : "[name]-[contenthash].js",
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
},
chunkFilename: chunkFilename:
isProdBuild && !isStatsBuild ? "[chunkhash:8].js" : "[id].chunk.js", isProdBuild && !isStatsBuild ? "[id]-[contenthash].js" : "[name].js",
assetModuleFilename:
isProdBuild && !isStatsBuild ? "[id]-[contenthash][ext]" : "[id][ext]",
hashFunction: "xxhash64",
hashDigest: "base64url",
hashDigestLength: 11, // full length of 64 bit base64url
path: outputPath, path: outputPath,
publicPath, publicPath,
// To silence warning in worker plugin // To silence warning in worker plugin

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,39 +1,19 @@
import { HassEntity } from "home-assistant-js-websocket"; import { HassEntity } from "home-assistant-js-websocket";
import { HistoryStates } from "../../../src/data/history";
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
interface HistoryQueryParams { const generateStateHistory = (
filter_entity_id: string; state: HassEntity,
end_time: string; deltas,
} start_date: Date,
end_date: Date
const parseQuery = <T>(queryString: string) => { ) => {
const query: any = {};
const items = queryString.split("&");
for (const item of items) {
const parts = item.split("=");
const key = decodeURIComponent(parts[0]);
const value = parts.length > 1 ? decodeURIComponent(parts[1]) : undefined;
query[key] = value;
}
return query as T;
};
const getTime = (minutesAgo) => {
const ts = new Date(Date.now() - minutesAgo * 60 * 1000);
return ts.toISOString();
};
const randomTimeAdjustment = (diff) => Math.random() * diff - diff / 2;
const maxTime = 1440;
const generateHistory = (state, deltas) => {
const changes = const changes =
typeof deltas[0] === "object" typeof deltas[0] === "object"
? deltas ? deltas
: deltas.map((st) => ({ state: st })); : deltas.map((st) => ({ state: st }));
const timeDiff = 900 / changes.length; const timeDiff = (end_date.getTime() - start_date.getTime()) / changes.length;
return changes.map((change, index) => { return changes.map((change, index) => {
let attributes; let attributes;
@@ -47,17 +27,13 @@ const generateHistory = (state, deltas) => {
attributes = { ...state.attributes, ...change.attributes }; attributes = { ...state.attributes, ...change.attributes };
} }
const time = const time = start_date.getTime() + timeDiff * index;
index === 0
? getTime(maxTime)
: getTime(maxTime - index * timeDiff + randomTimeAdjustment(timeDiff));
return { return {
attributes, a: attributes,
entity_id: state.entity_id, s: change.state || state.state,
state: change.state || state.state, lc: time / 1000,
last_changed: time, lu: time / 1000,
last_updated: time,
}; };
}); });
}; };
@@ -65,15 +41,29 @@ const generateHistory = (state, deltas) => {
const incrementalUnits = ["clients", "queries", "ads"]; const incrementalUnits = ["clients", "queries", "ads"];
export const mockHistory = (mockHass: MockHomeAssistant) => { export const mockHistory = (mockHass: MockHomeAssistant) => {
mockHass.mockAPI( mockHass.mockWS(
/history\/period\/.+/, "history/stream",
(hass, _method, path, _parameters) => { (
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]); {
const entities = params.filter_entity_id.split(","); entity_ids,
start_time,
end_time,
}: {
entity_ids: string[];
start_time: string;
end_time?: string;
},
hass,
onChange
) => {
const states: HistoryStates = {};
const results: HassEntity[][] = []; const start = new Date(start_time);
const end = end_time ? new Date(end_time) : new Date();
for (const entityId of entity_ids) {
states[entityId] = [];
for (const entityId of entities) {
const state = hass.states[entityId]; const state = hass.states[entityId];
if (!state) { if (!state) {
@@ -81,7 +71,12 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
} }
if (!state.attributes.unit_of_measurement) { if (!state.attributes.unit_of_measurement) {
results.push(generateHistory(state, [state.state])); states[entityId] = generateStateHistory(
state,
[state.state],
start,
end
);
continue; continue;
} }
@@ -120,17 +115,23 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
numberState - diff + Math.floor(Math.random() * 2 * diff); numberState - diff + Math.floor(Math.random() * 2 * diff);
} }
results.push( states[entityId] = generateStateHistory(
generateHistory( state,
{ Array.from({ length: statesToGenerate }, genFunc),
entity_id: state.entity_id, start,
attributes: state.attributes, end
},
Array.from({ length: statesToGenerate }, genFunc)
)
); );
} }
return results;
setTimeout(() => {
onChange?.({
states,
start_time: start,
end_time: end,
});
}, 1);
return () => {};
} }
); );
}; };

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

@@ -114,9 +114,6 @@ class HassioAddonAudio extends LitElement {
ha-card { ha-card {
display: block; display: block;
} }
paper-item {
width: 450px;
}
.card-actions { .card-actions {
text-align: right; text-align: right;
} }

View File

@@ -248,9 +248,9 @@ export class HassioBackups extends LitElement {
class="warning" class="warning"
@click=${this._deleteSelected} @click=${this._deleteSelected}
></ha-icon-button> ></ha-icon-button>
<paper-tooltip animation-delay="0" for="delete-btn"> <simple-tooltip animation-delay="0" for="delete-btn">
${this.supervisor.localize("backup.delete_selected")} ${this.supervisor.localize("backup.delete_selected")}
</paper-tooltip> </simple-tooltip>
`} `}
</div> </div>
</div> ` </div> `

View File

@@ -50,20 +50,7 @@ class HassioMarkdownDialog extends LitElement {
haStyleDialog, haStyleDialog,
hassioStyle, hassioStyle,
css` css`
app-toolbar {
margin: 0;
padding: 0 16px;
color: var(--primary-text-color);
background-color: var(--secondary-background-color);
}
app-toolbar [main-title] {
margin-left: 16px;
}
@media all and (max-width: 450px), all and (max-height: 500px) { @media all and (max-width: 450px), all and (max-height: 500px) {
app-toolbar {
color: var(--text-primary-color);
background-color: var(--primary-color);
}
ha-markdown { ha-markdown {
padding: 16px; padding: 16px;
} }

View File

@@ -597,10 +597,6 @@ export class DialogHassioNetwork
margin-left: 8px; margin-left: 8px;
} }
:host([rtl]) app-toolbar {
direction: rtl;
text-align: right;
}
.container { .container {
padding: 0 8px 4px; padding: 0 8px 4px;
} }

View File

@@ -4,7 +4,7 @@ import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item-body";
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators"; import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
@@ -128,7 +128,7 @@ class HassioRepositoriesDialog extends LitElement {
@click=${this._removeRepository} @click=${this._removeRepository}
> >
</ha-icon-button> </ha-icon-button>
<paper-tooltip <simple-tooltip
animation-delay="0" animation-delay="0"
position="bottom" position="bottom"
offset="1" offset="1"
@@ -138,7 +138,7 @@ class HassioRepositoriesDialog extends LitElement {
? "dialog.repositories.used" ? "dialog.repositories.used"
: "dialog.repositories.remove" : "dialog.repositories.remove"
)} )}
</paper-tooltip> </simple-tooltip>
</div> </div>
</paper-item> </paper-item>
` `

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,19 +19,20 @@
"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",
"@codemirror/commands": "6.2.2", "@codemirror/commands": "6.2.2",
"@codemirror/language": "6.6.0", "@codemirror/language": "6.6.0",
"@codemirror/legacy-modes": "6.3.1", "@codemirror/legacy-modes": "6.3.2",
"@codemirror/search": "6.2.3", "@codemirror/search": "6.3.0",
"@codemirror/state": "6.2.0", "@codemirror/state": "6.2.0",
"@codemirror/view": "6.9.2", "@codemirror/view": "6.9.3",
"@egjs/hammerjs": "2.0.17", "@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.5.1", "@formatjs/intl-datetimeformat": "6.5.1",
"@formatjs/intl-getcanonicallocales": "2.1.0", "@formatjs/intl-getcanonicallocales": "2.1.0",
@@ -39,14 +40,16 @@
"@formatjs/intl-numberformat": "8.3.5", "@formatjs/intl-numberformat": "8.3.5",
"@formatjs/intl-pluralrules": "5.1.10", "@formatjs/intl-pluralrules": "5.1.10",
"@formatjs/intl-relativetimeformat": "11.1.10", "@formatjs/intl-relativetimeformat": "11.1.10",
"@fullcalendar/core": "6.1.4", "@fullcalendar/core": "6.1.5",
"@fullcalendar/daygrid": "6.1.4", "@fullcalendar/daygrid": "6.1.5",
"@fullcalendar/interaction": "6.1.4", "@fullcalendar/interaction": "6.1.5",
"@fullcalendar/list": "6.1.4", "@fullcalendar/list": "6.1.5",
"@fullcalendar/timegrid": "6.1.4", "@fullcalendar/timegrid": "6.1.5",
"@lezer/highlight": "1.1.3", "@lezer/highlight": "1.1.4",
"@lit-labs/context": "0.3.0",
"@lit-labs/motion": "1.0.3", "@lit-labs/motion": "1.0.3",
"@lit-labs/virtualizer": "1.0.1", "@lit-labs/virtualizer": "1.0.1",
"@lrnwebcomponents/simple-tooltip": "4.1.0",
"@material/chips": "=14.0.0-canary.53b3cad2f.0", "@material/chips": "=14.0.0-canary.53b3cad2f.0",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0", "@material/data-table": "=14.0.0-canary.53b3cad2f.0",
"@material/mwc-button": "0.27.0", "@material/mwc-button": "0.27.0",
@@ -69,35 +72,33 @@
"@material/mwc-tab-bar": "0.27.0", "@material/mwc-tab-bar": "0.27.0",
"@material/mwc-textarea": "0.27.0", "@material/mwc-textarea": "0.27.0",
"@material/mwc-textfield": "0.27.0", "@material/mwc-textfield": "0.27.0",
"@material/mwc-top-app-bar": "0.27.0",
"@material/mwc-top-app-bar-fixed": "0.27.0", "@material/mwc-top-app-bar-fixed": "0.27.0",
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0", "@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
"@material/web": "=1.0.0-pre.4", "@material/web": "=1.0.0-pre.4",
"@mdi/js": "7.1.96", "@mdi/js": "7.2.96",
"@mdi/svg": "7.1.96", "@mdi/svg": "7.2.96",
"@polymer/app-layout": "3.1.0", "@polymer/app-layout": "3.1.0",
"@polymer/iron-flex-layout": "3.0.1", "@polymer/iron-flex-layout": "3.0.1",
"@polymer/iron-icon": "3.0.1",
"@polymer/iron-input": "3.0.1", "@polymer/iron-input": "3.0.1",
"@polymer/iron-resizable-behavior": "3.0.1", "@polymer/iron-resizable-behavior": "3.0.1",
"@polymer/paper-input": "3.2.1", "@polymer/paper-input": "3.2.1",
"@polymer/paper-item": "3.0.1", "@polymer/paper-item": "3.0.1",
"@polymer/paper-listbox": "3.0.1", "@polymer/paper-listbox": "3.0.1",
"@polymer/paper-slider": "3.0.1", "@polymer/paper-slider": "3.0.1",
"@polymer/paper-styles": "3.0.1",
"@polymer/paper-tabs": "3.1.0", "@polymer/paper-tabs": "3.1.0",
"@polymer/paper-toast": "3.0.1", "@polymer/paper-toast": "3.0.1",
"@polymer/paper-tooltip": "3.0.1", "@polymer/polymer": "3.5.1",
"@polymer/polymer": "3.4.1",
"@thomasloven/round-slider": "0.6.0", "@thomasloven/round-slider": "0.6.0",
"@vaadin/combo-box": "23.3.8", "@vaadin/combo-box": "23.3.9",
"@vaadin/vaadin-themable-mixin": "23.3.8", "@vaadin/vaadin-themable-mixin": "23.3.9",
"@vibrant/color": "3.2.1-alpha.1", "@vibrant/color": "3.2.1-alpha.1",
"@vibrant/core": "3.2.1-alpha.1", "@vibrant/core": "3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1", "@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
"@vue/web-component-wrapper": "1.3.0", "@vue/web-component-wrapper": "1.3.0",
"@webcomponents/scoped-custom-element-registry": "0.0.8", "@webcomponents/scoped-custom-element-registry": "0.0.8",
"@webcomponents/webcomponentsjs": "2.7.0", "@webcomponents/webcomponentsjs": "2.7.0",
"app-datepicker": "6.0.0-rc.32", "app-datepicker": "5.1.1",
"chart.js": "3.3.2", "chart.js": "3.3.2",
"comlink": "4.4.1", "comlink": "4.4.1",
"core-js": "3.29.1", "core-js": "3.29.1",
@@ -108,15 +109,15 @@
"deep-freeze": "0.0.1", "deep-freeze": "0.0.1",
"fuse.js": "6.6.2", "fuse.js": "6.6.2",
"google-timezones-json": "1.0.2", "google-timezones-json": "1.0.2",
"hls.js": "1.3.4", "hls.js": "1.3.5",
"home-assistant-js-websocket": "8.0.1", "home-assistant-js-websocket": "8.0.1",
"idb-keyval": "6.2.0", "idb-keyval": "6.2.0",
"intl-messageformat": "10.3.1", "intl-messageformat": "10.3.3",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"leaflet": "1.9.3", "leaflet": "1.9.3",
"leaflet-draw": "1.0.4", "leaflet-draw": "1.0.4",
"lit": "2.6.1", "lit": "2.7.0",
"marked": "4.2.12", "marked": "4.3.0",
"memoize-one": "6.0.0", "memoize-one": "6.0.0",
"node-vibrant": "3.2.1-alpha.1", "node-vibrant": "3.2.1-alpha.1",
"proxy-polyfill": "0.3.2", "proxy-polyfill": "0.3.2",
@@ -133,8 +134,8 @@
"tsparticles-engine": "2.9.3", "tsparticles-engine": "2.9.3",
"tsparticles-preset-links": "2.9.3", "tsparticles-preset-links": "2.9.3",
"unfetch": "5.0.0", "unfetch": "5.0.0",
"vis-data": "7.1.4", "vis-data": "7.1.6",
"vis-network": "9.1.4", "vis-network": "9.1.6",
"vue": "2.7.14", "vue": "2.7.14",
"vue2-daterange-picker": "0.6.8", "vue2-daterange-picker": "0.6.8",
"weekstart": "2.0.0", "weekstart": "2.0.0",
@@ -150,7 +151,6 @@
"@babel/core": "7.21.3", "@babel/core": "7.21.3",
"@babel/plugin-external-helpers": "7.18.6", "@babel/plugin-external-helpers": "7.18.6",
"@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-class-static-block": "7.21.0",
"@babel/plugin-proposal-decorators": "7.21.0", "@babel/plugin-proposal-decorators": "7.21.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6", "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
"@babel/plugin-proposal-object-rest-spread": "7.20.7", "@babel/plugin-proposal-object-rest-spread": "7.20.7",
@@ -173,6 +173,7 @@
"@types/chromecast-caf-sender": "1.0.5", "@types/chromecast-caf-sender": "1.0.5",
"@types/esprima": "4.0.3", "@types/esprima": "4.0.3",
"@types/glob": "8.1.0", "@types/glob": "8.1.0",
"@types/html-minifier-terser": "7.0.0",
"@types/js-yaml": "4.0.5", "@types/js-yaml": "4.0.5",
"@types/leaflet": "1.9.3", "@types/leaflet": "1.9.3",
"@types/leaflet-draw": "1.0.6", "@types/leaflet-draw": "1.0.6",
@@ -183,18 +184,18 @@
"@types/sortablejs": "1.15.1", "@types/sortablejs": "1.15.1",
"@types/tar": "6.1.4", "@types/tar": "6.1.4",
"@types/webspeechapi": "0.0.29", "@types/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "5.55.0", "@typescript-eslint/eslint-plugin": "5.57.0",
"@typescript-eslint/parser": "5.55.0", "@typescript-eslint/parser": "5.57.0",
"@web/dev-server": "0.1.36", "@web/dev-server": "0.1.37",
"@web/dev-server-rollup": "0.4.0", "@web/dev-server-rollup": "0.4.0",
"babel-loader": "9.1.2", "babel-loader": "9.1.2",
"babel-plugin-template-html-minifier": "4.1.0", "babel-plugin-template-html-minifier": "4.1.0",
"chai": "4.3.7", "chai": "4.3.7",
"del": "7.0.0", "del": "7.0.0",
"eslint": "8.36.0", "eslint": "8.37.0",
"eslint-config-airbnb-base": "15.0.0", "eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "17.0.0", "eslint-config-airbnb-typescript": "17.0.0",
"eslint-config-prettier": "8.7.0", "eslint-config-prettier": "8.8.0",
"eslint-import-resolver-webpack": "0.13.2", "eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-disable": "2.0.3", "eslint-plugin-disable": "2.0.3",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",
@@ -204,15 +205,15 @@
"eslint-plugin-wc": "1.4.0", "eslint-plugin-wc": "1.4.0",
"esprima": "4.0.1", "esprima": "4.0.1",
"fancy-log": "2.0.0", "fancy-log": "2.0.0",
"fs-extra": "11.1.0", "fs-extra": "11.1.1",
"glob": "9.3.0", "glob": "9.3.2",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-flatmap": "1.0.2", "gulp-flatmap": "1.0.2",
"gulp-json-transform": "0.4.8", "gulp-json-transform": "0.4.8",
"gulp-merge-json": "2.1.2", "gulp-merge-json": "2.1.2",
"gulp-rename": "2.0.0", "gulp-rename": "2.0.0",
"gulp-zopfli-green": "6.0.1", "gulp-zopfli-green": "6.0.1",
"html-minifier": "4.0.0", "html-minifier-terser": "7.1.0",
"husky": "8.0.3", "husky": "8.0.3",
"instant-mocha": "1.5.0", "instant-mocha": "1.5.0",
"jszip": "3.10.1", "jszip": "3.10.1",
@@ -226,16 +227,15 @@
"object-hash": "3.0.0", "object-hash": "3.0.0",
"open": "8.4.2", "open": "8.4.2",
"pinst": "3.0.0", "pinst": "3.0.0",
"prettier": "2.8.4", "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.0", "systemjs": "6.14.1",
"tar": "6.1.13", "tar": "6.1.13",
"terser-webpack-plugin": "5.3.7", "terser-webpack-plugin": "5.3.7",
"ts-lit-plugin": "1.2.1", "ts-lit-plugin": "1.2.1",
@@ -244,16 +244,16 @@
"vinyl-source-stream": "2.0.0", "vinyl-source-stream": "2.0.0",
"webpack": "=5.72.1", "webpack": "=5.72.1",
"webpack-cli": "5.0.1", "webpack-cli": "5.0.1",
"webpack-dev-server": "4.12.0", "webpack-dev-server": "4.13.1",
"webpack-manifest-plugin": "5.0.0", "webpack-manifest-plugin": "5.0.0",
"webpackbar": "5.0.2", "webpackbar": "5.0.2",
"workbox-build": "6.5.4" "workbox-build": "6.5.4"
}, },
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch", "_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
"resolutions": { "resolutions": {
"@polymer/polymer": "patch:@polymer/polymer@3.4.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"
}, },
"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 = "20230309.0" version = "20230401.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

@@ -1,9 +1,9 @@
import "@polymer/paper-item/paper-item"; import "@material/mwc-list";
import "@polymer/paper-item/paper-item-body";
import { css, html, LitElement } from "lit"; import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event"; import { fireEvent } from "../common/dom/fire_event";
import "../components/ha-icon-next"; import "../components/ha-icon-next";
import "../components/ha-list-item";
import { AuthProvider } from "../data/auth"; import { AuthProvider } from "../data/auth";
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
@@ -20,18 +20,21 @@ export class HaPickAuthProvider extends litLocalizeLiteMixin(LitElement) {
protected render() { protected render() {
return html` return html`
<p>${this.localize("ui.panel.page-authorize.pick_auth_provider")}:</p> <p>${this.localize("ui.panel.page-authorize.pick_auth_provider")}:</p>
${this.authProviders.map( <mwc-list>
(provider) => html` ${this.authProviders.map(
<paper-item (provider) => html`
role="button" <ha-list-item
.auth_provider=${provider} hasMeta
@click=${this._handlePick} role="button"
> .auth_provider=${provider}
<paper-item-body>${provider.name}</paper-item-body> @click=${this._handlePick}
<ha-icon-next></ha-icon-next> >
</paper-item> ${provider.name}
` <ha-icon-next slot="meta"></ha-icon-next>
)} </ha-list-item>
`
)}</mwc-list
>
`; `;
} }
@@ -40,11 +43,12 @@ export class HaPickAuthProvider extends litLocalizeLiteMixin(LitElement) {
} }
static styles = css` static styles = css`
paper-item {
cursor: pointer;
}
p { p {
margin-top: 0; margin-top: 0;
} }
mwc-list {
margin: 0 -16px;
--mdc-list-side-padding: 16px;
}
`; `;
} }

View File

@@ -1,16 +1,19 @@
import secondsToDuration from "./seconds_to_duration"; import millisecondsToDuration from "./milliseconds_to_duration";
const DAY_IN_SECONDS = 86400; const DAY_IN_MILLISECONDS = 86400000;
const HOUR_IN_SECONDS = 3600; const HOUR_IN_MILLISECONDS = 3600000;
const MINUTE_IN_SECONDS = 60; const MINUTE_IN_MILLISECONDS = 60000;
const SECOND_IN_MILLISECONDS = 1000;
export const UNIT_TO_SECOND_CONVERT = { export const UNIT_TO_MILLISECOND_CONVERT = {
s: 1, ms: 1,
min: MINUTE_IN_SECONDS, s: SECOND_IN_MILLISECONDS,
h: HOUR_IN_SECONDS, min: MINUTE_IN_MILLISECONDS,
d: DAY_IN_SECONDS, h: HOUR_IN_MILLISECONDS,
d: DAY_IN_MILLISECONDS,
}; };
export const formatDuration = (duration: string, units: string): string => export const formatDuration = (duration: string, units: string): string =>
secondsToDuration(parseFloat(duration) * UNIT_TO_SECOND_CONVERT[units]) || millisecondsToDuration(
"0"; parseFloat(duration) * UNIT_TO_MILLISECOND_CONVERT[units]
) || "0";

View File

@@ -0,0 +1,25 @@
const leftPad = (num: number, digits = 2) => {
let paddedNum = "" + num;
for (let i = 1; i < digits; i++) {
paddedNum = parseInt(paddedNum) < 10 ** i ? `0${paddedNum}` : paddedNum;
}
return paddedNum;
};
export default function millisecondsToDuration(d: number) {
const h = Math.floor(d / 1000 / 3600);
const m = Math.floor(((d / 1000) % 3600) / 60);
const s = Math.floor(((d / 1000) % 3600) % 60);
const ms = Math.floor(d % 1000);
if (h > 0) {
return `${h}:${leftPad(m)}:${leftPad(s)}`;
}
if (m > 0) {
return `${m}:${leftPad(s)}`;
}
if (s > 0 || ms > 0) {
return `${s}${ms > 0 ? `.${leftPad(ms, 3)}` : ``}`;
}
return null;
}

View File

@@ -0,0 +1,111 @@
import { PropertyDeclaration, PropertyValues, ReactiveElement } from "lit";
import { ClassElement } from "../../types";
import { shallowEqual } from "../util/shallow-equal";
/**
* Transform function type.
*/
export interface Transformer<T = any, V = any> {
(value: V): T;
}
type ReactiveTransformElement = ReactiveElement & {
_transformers: Map<PropertyKey, Transformer>;
_watching: Map<PropertyKey, Set<PropertyKey>>;
};
type ReactiveElementClassWithTransformers = typeof ReactiveElement & {
prototype: ReactiveTransformElement;
};
/**
* Specifies an tranformer callback that is run when the value of the decorated property, or any of the properties in the watching array, changes.
* The result of the tranformer is assigned to the decorated property.
* The tranformer receives the current as arguments.
*/
export const transform =
<T, V>(config: {
transformer: Transformer<T, V>;
watch?: PropertyKey[];
propertyOptions?: PropertyDeclaration;
}): any =>
(clsElement: ClassElement) => {
const key = String(clsElement.key);
return {
...clsElement,
kind: "method",
descriptor: {
set(this: ReactiveTransformElement, value: V) {
const oldValue = this[`__transform_${key}`];
const trnsformr: Transformer<T, V> | undefined =
this._transformers.get(key);
if (trnsformr) {
this[`__transform_${key}`] = trnsformr.call(this, value);
} else {
this[`__transform_${key}`] = value;
}
this[`__original_${key}`] = value;
this.requestUpdate(key, oldValue);
},
get(): T {
return this[`__transform_${key}`];
},
enumerable: true,
configurable: true,
},
finisher(cls: ReactiveElementClassWithTransformers) {
// if we haven't wrapped `willUpdate` in this class, do so
if (!cls.prototype._transformers) {
cls.prototype._transformers = new Map<PropertyKey, Transformer>();
cls.prototype._watching = new Map<PropertyKey, Set<PropertyKey>>();
// @ts-ignore
const userWillUpdate = cls.prototype.willUpdate;
// @ts-ignore
cls.prototype.willUpdate = function (
this: ReactiveTransformElement,
changedProperties: PropertyValues
) {
userWillUpdate.call(this, changedProperties);
const keys = new Set<PropertyKey>();
changedProperties.forEach((_v, k) => {
const watchers = this._watching;
const ks: Set<PropertyKey> | undefined = watchers.get(k);
if (ks !== undefined) {
ks.forEach((wk) => keys.add(wk));
}
});
keys.forEach((k) => {
// trigger setter
this[k] = this[`__original_${String(k)}`];
});
};
// clone any existing observers (superclasses)
// eslint-disable-next-line no-prototype-builtins
} else if (!cls.prototype.hasOwnProperty("_transformers")) {
const tranformers = cls.prototype._transformers;
cls.prototype._transformers = new Map();
tranformers.forEach((v: any, k: PropertyKey) =>
cls.prototype._transformers.set(k, v)
);
}
// set this method
cls.prototype._transformers.set(clsElement.key, config.transformer);
if (config.watch) {
// store watchers
config.watch.forEach((k) => {
let curWatch = cls.prototype._watching.get(k);
if (!curWatch) {
curWatch = new Set();
cls.prototype._watching.set(k, curWatch);
}
curWatch.add(clsElement.key);
});
}
cls.createProperty(clsElement.key, {
noAccessor: true,
hasChanged: (v: any, o: any) => !shallowEqual(v, o),
...config.propertyOptions,
});
},
};
};

View File

@@ -93,7 +93,7 @@ export const applyThemesOnElement = (
} }
// Nothing was changed // Nothing was changed
if (element._themes?.cacheKey === cacheKey) { if (element.__themes?.cacheKey === cacheKey) {
return; return;
} }
} }
@@ -119,7 +119,7 @@ export const applyThemesOnElement = (
} }
} }
if (!element._themes?.keys && !Object.keys(themeRules).length) { if (!element.__themes?.keys && !Object.keys(themeRules).length) {
// No styles to reset, and no styles to set // No styles to reset, and no styles to set
return; return;
} }
@@ -130,8 +130,8 @@ export const applyThemesOnElement = (
: undefined; : undefined;
// Add previous set keys to reset them, and new theme // Add previous set keys to reset them, and new theme
const styles = { ...element._themes?.keys, ...newTheme?.styles }; const styles = { ...element.__themes?.keys, ...newTheme?.styles };
element._themes = { cacheKey, keys: newTheme?.keys }; element.__themes = { cacheKey, keys: newTheme?.keys };
// Set and/or reset styles // Set and/or reset styles
if (element.updateStyles) { if (element.updateStyles) {

View File

@@ -7,7 +7,10 @@ import {
UPDATE_SUPPORT_PROGRESS, UPDATE_SUPPORT_PROGRESS,
} from "../../data/update"; } from "../../data/update";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { formatDuration, UNIT_TO_SECOND_CONVERT } from "../datetime/duration"; import {
formatDuration,
UNIT_TO_MILLISECOND_CONVERT,
} from "../datetime/duration";
import { formatDate } from "../datetime/format_date"; import { formatDate } from "../datetime/format_date";
import { formatDateTime } from "../datetime/format_date_time"; import { formatDateTime } from "../datetime/format_date_time";
import { formatTime } from "../datetime/format_time"; import { formatTime } from "../datetime/format_time";
@@ -57,7 +60,7 @@ export const computeStateDisplayFromEntityAttributes = (
if ( if (
attributes.device_class === "duration" && attributes.device_class === "duration" &&
attributes.unit_of_measurement && attributes.unit_of_measurement &&
UNIT_TO_SECOND_CONVERT[attributes.unit_of_measurement] UNIT_TO_MILLISECOND_CONVERT[attributes.unit_of_measurement]
) { ) {
try { try {
return formatDuration(state, attributes.unit_of_measurement); return formatDuration(state, attributes.unit_of_measurement);

View File

@@ -118,24 +118,40 @@ const FIXED_DOMAIN_ATTRIBUTE_STATES = {
"window", "window",
], ],
}, },
device_tracker: {
source_type: ["bluetooth", "bluetooth_le", "gps", "router"],
},
fan: {
direction: ["forward", "reverse"],
},
humidifier: { humidifier: {
device_class: ["humidifier", "dehumidifier"], device_class: ["humidifier", "dehumidifier"],
}, },
media_player: { media_player: {
device_class: ["tv", "speaker", "receiver"], device_class: ["tv", "speaker", "receiver"],
media_content_type: [ media_content_type: [
"album",
"app", "app",
"artist",
"channel", "channel",
"channels",
"composer",
"contibuting_artist",
"episode", "episode",
"game", "game",
"genre",
"image", "image",
"movie", "movie",
"music", "music",
"playlist", "playlist",
"podcast",
"season",
"track",
"tvshow", "tvshow",
"url", "url",
"video", "video",
], ],
repeat: ["off", "one", "all"],
}, },
number: { number: {
device_class: ["temperature"], device_class: ["temperature"],

View File

@@ -1,6 +1,7 @@
/** Return an color representing a state. */ /** Return an color representing a state. */
import { HassEntity } from "home-assistant-js-websocket"; import { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE } from "../../data/entity"; import { UNAVAILABLE } from "../../data/entity";
import { computeGroupDomain, GroupEntity } from "../../data/group";
import { computeCssVariable } from "../../resources/css-variables"; import { computeCssVariable } from "../../resources/css-variables";
import { slugify } from "../string/slugify"; import { slugify } from "../string/slugify";
import { batteryStateColorProperty } from "./color/battery_color"; import { batteryStateColorProperty } from "./color/battery_color";
@@ -52,11 +53,11 @@ export const stateColorCss = (stateObj: HassEntity, state?: string) => {
}; };
export const domainStateColorProperties = ( export const domainStateColorProperties = (
domain: string,
stateObj: HassEntity, stateObj: HassEntity,
state?: string state?: string
): string[] => { ): string[] => {
const compareState = state !== undefined ? state : stateObj.state; const compareState = state !== undefined ? state : stateObj.state;
const domain = computeDomain(stateObj.entity_id);
const active = stateActive(stateObj, state); const active = stateActive(stateObj, state);
const properties: string[] = []; const properties: string[] = [];
@@ -95,8 +96,16 @@ export const stateColorProperties = (
} }
} }
// Special rules for group coloring
if (domain === "group") {
const groupDomain = computeGroupDomain(stateObj as GroupEntity);
if (groupDomain && STATE_COLORED_DOMAIN.has(groupDomain)) {
return domainStateColorProperties(groupDomain, stateObj, state);
}
}
if (STATE_COLORED_DOMAIN.has(domain)) { if (STATE_COLORED_DOMAIN.has(domain)) {
return domainStateColorProperties(stateObj, state); return domainStateColorProperties(domain, stateObj, state);
} }
return undefined; return undefined;

View File

@@ -0,0 +1,108 @@
/**
* Compares two values for shallow equality, only 1 level deep.
*/
export const shallowEqual = (a: any, b: any): boolean => {
if (a === b) {
return true;
}
if (a && b && typeof a === "object" && typeof b === "object") {
if (a.constructor !== b.constructor) {
return false;
}
let i: number | [any, any];
let length: number;
if (Array.isArray(a)) {
length = a.length;
if (length !== b.length) {
return false;
}
for (i = length; i-- !== 0; ) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
if (a instanceof Map && b instanceof Map) {
if (a.size !== b.size) {
return false;
}
for (i of a.entries()) {
if (!b.has(i[0])) {
return false;
}
}
for (i of a.entries()) {
if (i[1] !== b.get(i[0])) {
return false;
}
}
return true;
}
if (a instanceof Set && b instanceof Set) {
if (a.size !== b.size) {
return false;
}
for (i of a.entries()) {
if (!b.has(i[0])) {
return false;
}
}
return true;
}
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
// @ts-ignore
length = a.length;
// @ts-ignore
if (length !== b.length) {
return false;
}
for (i = length; i-- !== 0; ) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
if (a.constructor === RegExp) {
return a.source === b.source && a.flags === b.flags;
}
if (a.valueOf !== Object.prototype.valueOf) {
return a.valueOf() === b.valueOf();
}
if (a.toString !== Object.prototype.toString) {
return a.toString() === b.toString();
}
const keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) {
return false;
}
for (i = length; i-- !== 0; ) {
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
return false;
}
}
for (i = length; i-- !== 0; ) {
const key = keys[i];
if (a[key] !== b[key]) {
return false;
}
}
return true;
}
// true if both NaN, false otherwise
// eslint-disable-next-line no-self-compare
return a !== a && b !== b;
};

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

@@ -48,8 +48,8 @@ class HaDataTableIcon extends LitElement {
outline: none; outline: none;
font-size: 10px; font-size: 10px;
line-height: 1; line-height: 1;
background-color: var(--paper-tooltip-background, #616161); background-color: var(--simple-tooltip-background, #616161);
color: var(--paper-tooltip-text-color, white); color: var(--simple-tooltip-text-color, white);
padding: 8px; padding: 8px;
border-radius: 2px; border-radius: 2px;
} }

View File

@@ -1,4 +1,4 @@
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import type { HassEntity } from "home-assistant-js-websocket"; import type { HassEntity } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
@@ -45,7 +45,7 @@ class StateInfo extends LitElement {
.datetime=${this.stateObj.last_changed} .datetime=${this.stateObj.last_changed}
capitalize capitalize
></ha-relative-time> ></ha-relative-time>
<paper-tooltip animation-delay="0" for="last_changed"> <simple-tooltip animation-delay="0" for="last_changed">
<div> <div>
<div class="row"> <div class="row">
<span class="column-name"> <span class="column-name">
@@ -72,7 +72,7 @@ class StateInfo extends LitElement {
></ha-relative-time> ></ha-relative-time>
</div> </div>
</div> </div>
</paper-tooltip> </simple-tooltip>
</div>` </div>`
: html`<div class="extra-info"><slot></slot></div>`} : html`<div class="extra-info"><slot></slot></div>`}
</div>`; </div>`;

View File

@@ -1,4 +1,4 @@
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event"; import { fireEvent } from "../common/dom/fire_event";
@@ -76,11 +76,11 @@ export class HaAnalytics extends LitElement {
</ha-switch> </ha-switch>
${!baseEnabled ${!baseEnabled
? html` ? html`
<paper-tooltip animation-delay="0" position="right"> <simple-tooltip animation-delay="0" position="right">
${this.hass.localize( ${this.hass.localize(
`ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled` `ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled`
)} )}
</paper-tooltip> </simple-tooltip>
` `
: ""} : ""}
</span> </span>

View File

@@ -1,13 +1,6 @@
// @ts-ignore // @ts-ignore
import chipStyles from "@material/chips/dist/mdc.chips.min.css"; import chipStyles from "@material/chips/dist/mdc.chips.min.css";
import { import { css, CSSResultGroup, html, LitElement, nothing, unsafeCSS } from "lit";
css,
CSSResultGroup,
html,
LitElement,
TemplateResult,
unsafeCSS,
} from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
@customElement("ha-chip") @customElement("ha-chip")
@@ -18,14 +11,14 @@ export class HaChip extends LitElement {
@property({ type: Boolean }) public noText = false; @property({ type: Boolean }) public noText = false;
protected render(): TemplateResult { protected render() {
return html` return html`
<div class="mdc-chip ${this.noText ? "no-text" : ""}"> <div class="mdc-chip ${this.noText ? "no-text" : ""}">
${this.hasIcon ${this.hasIcon
? html`<div class="mdc-chip__icon mdc-chip__icon--leading"> ? html`<div class="mdc-chip__icon mdc-chip__icon--leading">
<slot name="icon"></slot> <slot name="icon"></slot>
</div>` </div>`
: null} : nothing}
<div class="mdc-chip__ripple"></div> <div class="mdc-chip__ripple"></div>
<span role="gridcell"> <span role="gridcell">
<span role="button" tabindex="0" class="mdc-chip__primary-action"> <span role="button" tabindex="0" class="mdc-chip__primary-action">
@@ -36,7 +29,7 @@ export class HaChip extends LitElement {
? html`<div class="mdc-chip__icon mdc-chip__icon--trailing"> ? html`<div class="mdc-chip__icon mdc-chip__icon--trailing">
<slot name="trailing-icon"></slot> <slot name="trailing-icon"></slot>
</div>` </div>`
: null} : nothing}
</div> </div>
`; `;
} }

View File

@@ -85,6 +85,7 @@ export class HaControlButton extends LitElement {
--control-button-background-opacity: 0.2; --control-button-background-opacity: 0.2;
--control-button-border-radius: 10px; --control-button-border-radius: 10px;
--mdc-icon-size: 20px; --mdc-icon-size: 20px;
color: var(--primary-text-color);
width: 40px; width: 40px;
height: 40px; height: 40px;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
@@ -110,6 +111,8 @@ export class HaControlButton extends LitElement {
--mdc-ripple-color: var(--control-button-background-color); --mdc-ripple-color: var(--control-button-background-color);
/* For safari border-radius overflow */ /* For safari border-radius overflow */
z-index: 0; z-index: 0;
font-size: inherit;
color: inherit;
} }
.button::before { .button::before {
content: ""; content: "";

View File

@@ -25,8 +25,6 @@ export type ControlSelectOption = {
export class HaControlSelect extends LitElement { export class HaControlSelect extends LitElement {
@property({ type: Boolean, reflect: true }) disabled = false; @property({ type: Boolean, reflect: true }) disabled = false;
@property() public label?: string;
@property() public options?: ControlSelectOption[]; @property() public options?: ControlSelectOption[];
@property() public value?: string; @property() public value?: string;
@@ -100,10 +98,11 @@ export class HaControlSelect extends LitElement {
private _handleKeydown(ev: KeyboardEvent) { private _handleKeydown(ev: KeyboardEvent) {
if (!this.options || this._activeIndex == null || this.disabled) return; if (!this.options || this._activeIndex == null || this.disabled) return;
const value = this.options[this._activeIndex].value;
switch (ev.key) { switch (ev.key) {
case " ": case " ":
this.value = this.options[this._activeIndex].value; this.value = value;
fireEvent(this, "value-changed", { value: this.value }); fireEvent(this, "value-changed", { value });
break; break;
case "ArrowUp": case "ArrowUp":
case "ArrowLeft": case "ArrowLeft":
@@ -132,7 +131,7 @@ export class HaControlSelect extends LitElement {
if (this.disabled) return; if (this.disabled) return;
const value = (ev.target as any).value; const value = (ev.target as any).value;
this.value = value; this.value = value;
fireEvent(this, "value-changed", { value: this.value }); fireEvent(this, "value-changed", { value });
} }
private _handleOptionMouseDown(ev: MouseEvent) { private _handleOptionMouseDown(ev: MouseEvent) {
@@ -176,6 +175,7 @@ export class HaControlSelect extends LitElement {
.value=${option.value} .value=${option.value}
aria-selected=${this.value === option.value} aria-selected=${this.value === option.value}
aria-label=${ifDefined(option.label)} aria-label=${ifDefined(option.label)}
title=${ifDefined(option.label)}
@click=${this._handleOptionClick} @click=${this._handleOptionClick}
@mousedown=${this._handleOptionMouseDown} @mousedown=${this._handleOptionMouseDown}
@mouseup=${this._handleOptionMouseUp} @mouseup=${this._handleOptionMouseUp}
@@ -204,8 +204,11 @@ export class HaControlSelect extends LitElement {
--control-select-background: var(--disabled-color); --control-select-background: var(--disabled-color);
--control-select-background-opacity: 0.2; --control-select-background-opacity: 0.2;
--control-select-thickness: 40px; --control-select-thickness: 40px;
--control-select-border-radius: 12px; --control-select-border-radius: 10px;
--control-select-padding: 4px; --control-select-padding: 4px;
--control-select-button-border-radius: calc(
var(--control-select-border-radius) - var(--control-select-padding)
);
--mdc-icon-size: 20px; --mdc-icon-size: 20px;
height: var(--control-select-thickness); height: var(--control-select-thickness);
width: 100%; width: 100%;
@@ -262,9 +265,7 @@ export class HaControlSelect extends LitElement {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: calc( border-radius: var(--control-select-button-border-radius);
var(--control-select-border-radius) - var(--control-select-padding)
);
overflow: hidden; overflow: hidden;
color: var(--primary-text-color); color: var(--primary-text-color);
/* For safari border-radius overflow */ /* For safari border-radius overflow */
@@ -302,6 +303,14 @@ export class HaControlSelect extends LitElement {
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
text-align: center; text-align: center;
padding: 2px;
width: 100%;
box-sizing: border-box;
}
.option .content span {
display: block;
width: 100%;
hyphens: auto;
} }
:host([vertical]) { :host([vertical]) {
width: var(--control-select-thickness); width: var(--control-select-thickness);

View File

@@ -244,6 +244,7 @@ export class HaControlSlider extends LitElement {
})} })}
> >
<div class="slider-track-background"></div> <div class="slider-track-background"></div>
<slot name="background"></slot>
${this.mode === "cursor" ${this.mode === "cursor"
? this.value != null ? this.value != null
? html` ? html`
@@ -310,6 +311,13 @@ export class HaControlSlider extends LitElement {
background: var(--control-slider-background); background: var(--control-slider-background);
opacity: var(--control-slider-background-opacity); opacity: var(--control-slider-background-opacity);
} }
::slotted([slot="background"]) {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
.slider .slider-track-bar { .slider .slider-track-bar {
--border-radius: var(--control-slider-border-radius); --border-radius: var(--control-slider-border-radius);
--handle-size: 4px; --handle-size: 4px;
@@ -424,6 +432,7 @@ export class HaControlSlider extends LitElement {
bottom: 0; bottom: 0;
left: calc(var(--value, 0) * (100% - var(--cursor-size))); left: calc(var(--value, 0) * (100% - var(--cursor-size)));
width: var(--cursor-size); width: var(--cursor-size);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
} }
.slider .slider-track-cursor:after { .slider .slider-track-cursor:after {
height: 50%; height: 50%;

View File

@@ -41,14 +41,14 @@ export class HaDialogDatePicker extends LitElement {
return nothing; return nothing;
} }
return html`<ha-dialog open @closed=${this.closeDialog}> return html`<ha-dialog open @closed=${this.closeDialog}>
<app-date-picker <app-datepicker
.value=${this._value} .value=${this._value}
.min=${this._params.min} .min=${this._params.min}
.max=${this._params.max} .max=${this._params.max}
.locale=${this._params.locale} .locale=${this._params.locale}
@date-updated=${this._valueChanged} @datepicker-value-updated=${this._valueChanged}
.firstDayOfWeek=${this._params.firstWeekday} .firstDayOfWeek=${this._params.firstWeekday}
></app-date-picker> ></app-datepicker>
<mwc-button slot="secondaryAction" @click=${this._setToday}> <mwc-button slot="secondaryAction" @click=${this._setToday}>
${this.hass.localize("ui.dialogs.date-picker.today")} ${this.hass.localize("ui.dialogs.date-picker.today")}
</mwc-button> </mwc-button>
@@ -79,32 +79,35 @@ export class HaDialogDatePicker extends LitElement {
haStyleDialog, haStyleDialog,
css` css`
ha-dialog { ha-dialog {
--dialog-content-padding: 0;
--justify-action-buttons: space-between; --justify-action-buttons: space-between;
} }
app-date-picker { app-datepicker {
--app-focus: var(--primary-text-color); --app-datepicker-accent-color: var(--primary-color);
--app-hover: var(--primary-color); --app-datepicker-bg-color: transparent;
--app-on-disabled: var(--disabled-color); --app-datepicker-color: var(--primary-text-color);
--app-on-focus: var(--primary-text-color); --app-datepicker-disabled-day-color: var(--disabled-text-color);
--app-on-hover: var(--primary-text-color); --app-datepicker-focused-day-color: var(--text-primary-color);
--app-on-primary: var(--text-primary-color); --app-datepicker-focused-year-bg-color: var(--primary-color);
--app-on-surface: var(--primary-text-color); --app-datepicker-selector-color: var(--secondary-text-color);
--app-on-today: var(--primary-text-color); --app-datepicker-separator-color: var(--divider-color);
--app-on-week-number: var(--secondary-text-color); --app-datepicker-weekday-color: var(--secondary-text-color);
--app-on-weekday: var(--secondary-text-color);
--app-primary: var(--primary-color);
--app-selected-focus: var(--primary-text-color);
--app-selected-hover: var(--primary-color);
--app-selected-on-focus: var(--text-primary-color);
--app-selected-on-hover: var(--text-primary-color);
--app-shape: var(--mdc-shape-medium);
--app-surface: transparent;
--app-today: var(--primary-text-color);
margin: auto;
} }
ha-dialog { app-datepicker::part(calendar-day):focus {
--mdc-dialog-min-width: 300px; outline: none;
}
app-datepicker::part(body) {
direction: ltr;
}
@media all and (min-width: 450px) {
ha-dialog {
--mdc-dialog-min-width: 300px;
}
}
@media all and (max-width: 450px), all and (max-height: 500px) {
app-datepicker {
width: 100%;
}
} }
`, `,
]; ];

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

@@ -0,0 +1,25 @@
import { DrawerBase } from "@material/mwc-drawer/mwc-drawer-base";
import { styles } from "@material/mwc-drawer/mwc-drawer.css";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-drawer")
export class HaDrawer extends DrawerBase {
static override styles = [
styles,
css`
.mdc-drawer {
top: 0;
}
.mdc-drawer--modal.mdc-drawer--open {
left: min(0px, var(--drawer-modal-left-offset));
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-drawer": HaDrawer;
}
}

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

@@ -1,4 +1,4 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import "./ha-form"; import "./ha-form";
@@ -26,7 +26,7 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
@property() public computeHelper?: (schema: HaFormSchema) => string; @property() public computeHelper?: (schema: HaFormSchema) => string;
protected render(): TemplateResult { protected render() {
return html` return html`
<ha-expansion-panel outlined .expanded=${Boolean(this.schema.expanded)}> <ha-expansion-panel outlined .expanded=${Boolean(this.schema.expanded)}>
<div <div
@@ -38,7 +38,7 @@ export class HaFormExpendable extends LitElement implements HaFormElement {
? html` <ha-icon .icon=${this.schema.icon}></ha-icon> ` ? html` <ha-icon .icon=${this.schema.icon}></ha-icon> `
: this.schema.iconPath : this.schema.iconPath
? html` <ha-svg-icon .path=${this.schema.iconPath}></ha-svg-icon> ` ? html` <ha-svg-icon .path=${this.schema.iconPath}></ha-svg-icon> `
: null} : nothing}
${this.schema.title} ${this.schema.title}
</div> </div>
<div class="content"> <div class="content">

View File

@@ -32,6 +32,9 @@ export class HaHeaderBar extends LitElement {
return [ return [
unsafeCSS(topAppBarStyles), unsafeCSS(topAppBarStyles),
css` css`
.mdc-top-app-bar__row {
height: var(--header-height);
}
.mdc-top-app-bar { .mdc-top-app-bar {
position: static; position: static;
color: var(--mdc-theme-on-primary, #fff); color: var(--mdc-theme-on-primary, #fff);

View File

@@ -1,5 +1,5 @@
import { mdiHelpCircle } from "@mdi/js"; import { mdiHelpCircle } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { css, html, LitElement, TemplateResult } from "lit"; import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "./ha-svg-icon"; import "./ha-svg-icon";
@@ -13,11 +13,11 @@ export class HaHelpTooltip extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-svg-icon .path=${mdiHelpCircle}></ha-svg-icon> <ha-svg-icon .path=${mdiHelpCircle}></ha-svg-icon>
<paper-tooltip <simple-tooltip
offset="4" offset="4"
.position=${this.position} .position=${this.position}
.fitToVisibleBounds=${true} .fitToVisibleBounds=${true}
>${this.label}</paper-tooltip >${this.label}</simple-tooltip
> >
`; `;
} }

View File

@@ -1,6 +1,6 @@
import "@material/mwc-list/mwc-list-item"; import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js"; import { mdiDotsVertical } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { css, html, LitElement, TemplateResult } from "lit"; import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map"; import { classMap } from "lit/directives/class-map";
@@ -75,9 +75,12 @@ export class HaIconOverflowMenu extends LitElement {
? html`<div role="separator"></div>` ? html`<div role="separator"></div>`
: html`<div> : html`<div>
${item.tooltip ${item.tooltip
? html`<paper-tooltip animation-delay="0" position="left"> ? html`<simple-tooltip
animation-delay="0"
position="left"
>
${item.tooltip} ${item.tooltip}
</paper-tooltip>` </simple-tooltip>`
: ""} : ""}
<ha-icon-button <ha-icon-button
@click=${item.action} @click=${item.action}

View File

@@ -1,4 +1,3 @@
import "@polymer/iron-icon/iron-icon";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@@ -66,7 +65,8 @@ export class HaIcon extends LitElement {
return nothing; return nothing;
} }
if (this._legacy) { if (this._legacy) {
return html`<iron-icon .icon=${this.icon}></iron-icon>`; return html`<!-- @ts-ignore we don't provice the iron-icon element -->
<iron-icon .icon=${this.icon}></iron-icon>`;
} }
return html`<ha-svg-icon return html`<ha-svg-icon
.path=${this._path} .path=${this._path}

View File

@@ -1,5 +1,5 @@
import { mdiStar } from "@mdi/js"; import { mdiStar } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,

View File

@@ -2,7 +2,8 @@ import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import type { DurationSelector } from "../../data/selector"; import type { DurationSelector } from "../../data/selector";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { HaDurationData } from "../ha-duration-input"; import type { HaDurationData } from "../ha-duration-input";
import "../ha-duration-input";
@customElement("ha-selector-duration") @customElement("ha-selector-duration")
export class HaTimeDuration extends LitElement { export class HaTimeDuration extends LitElement {

View File

@@ -1,4 +1,3 @@
import "@polymer/paper-item/paper-item-body";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
@@ -13,13 +12,14 @@ export class HaSettingsRow extends LitElement {
return html` return html`
<div class="prefix-wrap"> <div class="prefix-wrap">
<slot name="prefix"></slot> <slot name="prefix"></slot>
<paper-item-body <div
class="body"
?two-line=${!this.threeLine} ?two-line=${!this.threeLine}
?three-line=${this.threeLine} ?three-line=${this.threeLine}
> >
<slot name="heading"></slot> <slot name="heading"></slot>
<div secondary><slot name="description"></slot></div> <div class="secondary"><slot name="description"></slot></div>
</paper-item-body> </div>
</div> </div>
<div class="content"><slot></slot></div> <div class="content"><slot></slot></div>
`; `;
@@ -34,10 +34,38 @@ export class HaSettingsRow extends LitElement {
align-self: auto; align-self: auto;
align-items: center; align-items: center;
} }
paper-item-body { .body {
padding: 8px 16px 8px 0; padding: 8px 16px 8px 0;
overflow: hidden;
display: var(--layout-vertical_-_display);
flex-direction: var(--layout-vertical_-_flex-direction);
justify-content: var(--layout-center-justified_-_justify-content);
flex: var(--layout-flex_-_flex);
flex-basis: var(--layout-flex_-_flex-basis);
} }
paper-item-body[two-line] { .body[three-line] {
min-height: var(--paper-item-body-three-line-min-height, 88px);
}
.body > * {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.body > .secondary {
font-family: var(--paper-font-body1_-_font-family);
-webkit-font-smoothing: var(
--paper-font-body1_-_-webkit-font-smoothing
);
font-size: var(--paper-font-body1_-_font-size);
font-weight: var(--paper-font-body1_-_font-weight);
line-height: var(--paper-font-body1_-_line-height);
color: var(
--paper-item-body-secondary-color,
var(--secondary-text-color)
);
}
.body[two-line] {
min-height: calc( min-height: calc(
var(--paper-item-body-two-line-min-height, 72px) - 16px var(--paper-item-body-two-line-min-height, 72px) - 16px
); );
@@ -64,7 +92,7 @@ export class HaSettingsRow extends LitElement {
::slotted(ha-switch) { ::slotted(ha-switch) {
padding: 16px 0; padding: 16px 0;
} }
div[secondary] { .secondary {
white-space: normal; white-space: normal;
} }
.prefix-wrap { .prefix-wrap {

View File

@@ -846,17 +846,9 @@ class HaSidebar extends SubscribeMixin(LitElement) {
-ms-user-select: none; -ms-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
border-right: 1px solid var(--divider-color);
background-color: var(--sidebar-background-color); background-color: var(--sidebar-background-color);
width: 56px; width: 100%;
} box-sizing: border-box;
:host([expanded]) {
width: 256px;
width: calc(256px + env(safe-area-inset-left));
}
:host([rtl]) {
border-right: 0;
border-left: 1px solid var(--divider-color);
} }
.menu { .menu {
height: var(--header-height); height: var(--header-height);
@@ -1070,8 +1062,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
.notification-badge, .notification-badge,
.configuration-badge { .configuration-badge {
left: calc(var(--app-drawer-width) - 42px);
position: absolute; position: absolute;
left: calc(var(--app-drawer-width, 248px) - 42px);
min-width: 20px; min-width: 20px;
box-sizing: border-box; box-sizing: border-box;
border-radius: 50%; border-radius: 50%;

View File

@@ -9,7 +9,7 @@ import {
mdiSofa, mdiSofa,
mdiUnfoldMoreVertical, mdiUnfoldMoreVertical,
} from "@mdi/js"; } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light"; import { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
import { HassEntity, HassServiceTarget } from "home-assistant-js-websocket"; import { HassEntity, HassServiceTarget } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, unsafeCSS, nothing } from "lit"; import { css, CSSResultGroup, html, LitElement, unsafeCSS, nothing } from "lit";
@@ -248,10 +248,10 @@ export class HaTargetPicker extends LitElement {
.type=${type} .type=${type}
@click=${this._handleExpand} @click=${this._handleExpand}
></ha-icon-button> ></ha-icon-button>
<paper-tooltip class="expand" animation-delay="0" <simple-tooltip class="expand" animation-delay="0"
>${this.hass.localize( >${this.hass.localize(
`ui.components.target-picker.expand_${type}` `ui.components.target-picker.expand_${type}`
)}</paper-tooltip )}</simple-tooltip
> >
</span>`} </span>`}
<span role="gridcell"> <span role="gridcell">
@@ -266,10 +266,10 @@ export class HaTargetPicker extends LitElement {
.type=${type} .type=${type}
@click=${this._handleRemove} @click=${this._handleRemove}
></ha-icon-button> ></ha-icon-button>
<paper-tooltip animation-delay="0" <simple-tooltip animation-delay="0"
>${this.hass.localize( >${this.hass.localize(
`ui.components.target-picker.remove_${type}` `ui.components.target-picker.remove_${type}`
)}</paper-tooltip )}</simple-tooltip
> >
</span> </span>
</div> </div>
@@ -670,7 +670,7 @@ export class HaTargetPicker extends LitElement {
.mdc-chip:hover { .mdc-chip:hover {
z-index: 5; z-index: 5;
} }
paper-tooltip.expand { simple-tooltip.expand {
min-width: 200px; min-width: 200px;
} }
:host([disabled]) .mdc-chip { :host([disabled]) .mdc-chip {

View File

@@ -0,0 +1,34 @@
import { TopAppBarFixedBase } from "@material/mwc-top-app-bar-fixed/mwc-top-app-bar-fixed-base";
import { styles } from "@material/mwc-top-app-bar/mwc-top-app-bar.css";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-top-app-bar-fixed")
export class HaTopAppBarFixed extends TopAppBarFixedBase {
static override styles = [
styles,
css`
.mdc-top-app-bar__row {
height: var(--header-height);
border-bottom: var(--app-header-border-bottom);
}
.mdc-top-app-bar--fixed-adjust {
padding-top: var(--header-height);
}
.mdc-top-app-bar {
--mdc-typography-headline6-font-weight: 400;
color: var(--app-header-text-color, var(--mdc-theme-on-primary, #fff));
background-color: var(
--app-header-background-color,
var(--mdc-theme-primary)
);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-top-app-bar-fixed": HaTopAppBarFixed;
}
}

View File

@@ -0,0 +1,34 @@
import { TopAppBarBase } from "@material/mwc-top-app-bar/mwc-top-app-bar-base";
import { styles } from "@material/mwc-top-app-bar/mwc-top-app-bar.css";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-top-app-bar")
export class HaTopAppBar extends TopAppBarBase {
static override styles = [
styles,
css`
.mdc-top-app-bar__row {
height: var(--header-height);
border-bottom: var(--app-header-border-bottom);
}
.mdc-top-app-bar--fixed-adjust {
padding-top: var(--header-height);
}
.mdc-top-app-bar {
--mdc-typography-headline6-font-weight: 400;
color: var(--app-header-text-color, var(--mdc-theme-on-primary, #fff));
background-color: var(
--app-header-background-color,
var(--mdc-theme-primary)
);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-top-app-bar": HaTopAppBar;
}
}

View File

@@ -50,6 +50,10 @@ export class HaMap extends ReactiveElement {
@property({ type: Boolean }) public autoFit = false; @property({ type: Boolean }) public autoFit = false;
@property({ type: Boolean }) public renderPassive = false;
@property({ type: Boolean }) public interactiveZones = false;
@property({ type: Boolean }) public fitZones?: boolean; @property({ type: Boolean }) public fitZones?: boolean;
@property({ type: Boolean }) public darkMode?: boolean; @property({ type: Boolean }) public darkMode?: boolean;
@@ -321,6 +325,10 @@ export class HaMap extends ReactiveElement {
const computedStyles = getComputedStyle(this); const computedStyles = getComputedStyle(this);
const zoneColor = computedStyles.getPropertyValue("--accent-color"); const zoneColor = computedStyles.getPropertyValue("--accent-color");
const passiveZoneColor = computedStyles.getPropertyValue(
"--secondary-text-color"
);
const darkPrimaryColor = computedStyles.getPropertyValue( const darkPrimaryColor = computedStyles.getPropertyValue(
"--dark-primary-color" "--dark-primary-color"
); );
@@ -350,7 +358,7 @@ export class HaMap extends ReactiveElement {
if (computeStateDomain(stateObj) === "zone") { if (computeStateDomain(stateObj) === "zone") {
// DRAW ZONE // DRAW ZONE
if (passive) { if (passive && !this.renderPassive) {
continue; continue;
} }
@@ -374,7 +382,7 @@ export class HaMap extends ReactiveElement {
iconSize: [24, 24], iconSize: [24, 24],
className, className,
}), }),
interactive: false, interactive: this.interactiveZones,
title, title,
}) })
); );
@@ -383,7 +391,7 @@ export class HaMap extends ReactiveElement {
this._mapZones.push( this._mapZones.push(
Leaflet.circle([latitude, longitude], { Leaflet.circle([latitude, longitude], {
interactive: false, interactive: false,
color: zoneColor, color: passive ? passiveZoneColor : zoneColor,
radius, radius,
}) })
); );

View File

@@ -5,7 +5,7 @@ import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item"; import "@material/mwc-list/mwc-list-item";
import { mdiArrowUpRight, mdiPlay, mdiPlus } from "@mdi/js"; import { mdiArrowUpRight, mdiPlay, mdiPlus } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@@ -600,8 +600,8 @@ export class HaMediaPlayerBrowse extends LitElement {
</div> </div>
<div class="title"> <div class="title">
${child.title} ${child.title}
<paper-tooltip fitToVisibleBounds position="top" offset="4" <simple-tooltip fitToVisibleBounds position="top" offset="4"
>${child.title}</paper-tooltip >${child.title}</simple-tooltip
> >
</div> </div>
</ha-card> </ha-card>

View File

@@ -1,4 +1,4 @@
import { CSSResultGroup, html, css, LitElement, TemplateResult } from "lit"; import { CSSResultGroup, html, css, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined"; import { ifDefined } from "lit/directives/if-defined";
@@ -8,12 +8,12 @@ export class HaTileImage extends LitElement {
@property() public imageAlt?: string; @property() public imageAlt?: string;
protected render(): TemplateResult { protected render() {
return html` return html`
<div class="image"> <div class="image">
${this.imageUrl ${this.imageUrl
? html`<img alt=${ifDefined(this.imageAlt)} src=${this.imageUrl} />` ? html`<img alt=${ifDefined(this.imageAlt)} src=${this.imageUrl} />`
: null} : nothing}
</div> </div>
`; `;
} }

Some files were not shown because too many files have changed in this diff Show More