custom-card-helpers 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +13 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +50 -0
- package/.github/workflows/release.yml +4 -0
- package/.github/workflows/test.yml +1 -0
- package/dist/compute-name.d.ts +7 -0
- package/dist/compute-state-display.d.ts +1 -2
- package/dist/datetime/duration_to_seconds.d.ts +1 -1
- package/dist/datetime/seconds_to_duration.d.ts +1 -1
- package/dist/datetime/select_unit.d.ts +8 -0
- package/dist/get-lovelace.d.ts +5 -1
- package/dist/index.js +259 -23
- package/dist/index.js.map +1 -1
- package/dist/index.m.js +254 -23
- package/dist/index.m.js.map +1 -1
- package/dist/index.umd.js +263 -25
- package/dist/index.umd.js.map +1 -1
- package/dist/scroll-to-target.d.ts +1 -1
- package/dist/translations/localize.d.ts +1 -2
- package/dist/turn-on-off-entity.d.ts +2 -0
- package/dist/types.d.ts +156 -4
- package/package.json +7 -8
- package/src/compute-name.ts +7 -0
- package/src/compute-state-display.ts +2 -3
- package/src/cover_icon.ts +74 -6
- package/src/datetime/duration_to_seconds.ts +1 -1
- package/src/datetime/relative_time.ts +1 -2
- package/src/datetime/seconds_to_duration.ts +1 -1
- package/src/datetime/select_unit.ts +94 -0
- package/src/datetime/timer_time_remaining.ts +1 -1
- package/src/get-lovelace.ts +22 -16
- package/src/handle-action.ts +19 -2
- package/src/handle-click.ts +1 -1
- package/src/scroll-to-target.ts +1 -1
- package/src/state_icon.ts +1 -1
- package/src/translations/localize.ts +1 -3
- package/src/turn-on-off-entity.ts +10 -0
- package/src/types.ts +203 -3
- package/test/datetime.test.ts +2 -2
- package/test/icons.test.ts +51 -0
- package/test/service-actions.test.ts +19 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Source - https://stackoverflow.com/a/66819358
|
|
2
|
+
# Posted by Johnny, modified by community. See post 'Timeline' for change history
|
|
3
|
+
# Retrieved 2026-02-27, License - CC BY-SA 4.0
|
|
4
|
+
|
|
5
|
+
version: 2
|
|
6
|
+
updates:
|
|
7
|
+
- package-ecosystem: "npm"
|
|
8
|
+
directory: "/"
|
|
9
|
+
schedule:
|
|
10
|
+
interval: "daily"
|
|
11
|
+
# Always increase the version requirement
|
|
12
|
+
# to match the new version.
|
|
13
|
+
versioning-strategy: increase
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Claude Code Review
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, ready_for_review, reopened]
|
|
6
|
+
# Optional: Only run on specific file changes
|
|
7
|
+
# paths:
|
|
8
|
+
# - "src/**/*.ts"
|
|
9
|
+
# - "src/**/*.tsx"
|
|
10
|
+
# - "src/**/*.js"
|
|
11
|
+
# - "src/**/*.jsx"
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude-review:
|
|
15
|
+
# Optional: Filter by PR author
|
|
16
|
+
# if: |
|
|
17
|
+
# github.event.pull_request.user.login == 'external-contributor' ||
|
|
18
|
+
# github.event.pull_request.user.login == 'new-developer' ||
|
|
19
|
+
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
|
20
|
+
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
pull-requests: read
|
|
25
|
+
issues: read
|
|
26
|
+
id-token: write
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout repository
|
|
30
|
+
uses: actions/checkout@v4
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 1
|
|
33
|
+
|
|
34
|
+
- name: Run Claude Code Review
|
|
35
|
+
id: claude-review
|
|
36
|
+
uses: anthropics/claude-code-action@v1
|
|
37
|
+
with:
|
|
38
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
39
|
+
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
|
40
|
+
plugins: 'code-review@claude-code-plugins'
|
|
41
|
+
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
|
42
|
+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
43
|
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
|
44
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Claude Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
pull_request_review_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
issues:
|
|
9
|
+
types: [opened, assigned]
|
|
10
|
+
pull_request_review:
|
|
11
|
+
types: [submitted]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude:
|
|
15
|
+
if: |
|
|
16
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
17
|
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
18
|
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
19
|
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
pull-requests: read
|
|
24
|
+
issues: read
|
|
25
|
+
id-token: write
|
|
26
|
+
actions: read # Required for Claude to read CI results on PRs
|
|
27
|
+
steps:
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 1
|
|
32
|
+
|
|
33
|
+
- name: Run Claude Code
|
|
34
|
+
id: claude
|
|
35
|
+
uses: anthropics/claude-code-action@v1
|
|
36
|
+
with:
|
|
37
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
|
+
|
|
39
|
+
# This is an optional setting that allows Claude to read CI results on PRs
|
|
40
|
+
additional_permissions: |
|
|
41
|
+
actions: read
|
|
42
|
+
|
|
43
|
+
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
|
44
|
+
# prompt: 'Update the pull request description to include a summary of changes.'
|
|
45
|
+
|
|
46
|
+
# Optional: Add claude_args to customize behavior and configuration
|
|
47
|
+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
48
|
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
|
49
|
+
# claude_args: '--allowed-tools Bash(gh pr *)'
|
|
50
|
+
|
package/dist/compute-name.d.ts
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
import { HassEntity } from "home-assistant-js-websocket";
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Reads `friendly_name`, which Home Assistant is moving away from -
|
|
4
|
+
* it now always includes the device name, so this duplicates context the
|
|
5
|
+
* surrounding UI already shows. Prefer `hass.formatEntityName(stateObj, name)`
|
|
6
|
+
* on HA 2026.4 and later, which resolves the name from the entity's registry
|
|
7
|
+
* context and lets users choose which parts to include.
|
|
8
|
+
*/
|
|
2
9
|
export declare const computeName: (stateObj: HassEntity) => string;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { HassEntity } from "home-assistant-js-websocket";
|
|
2
|
-
import { LocalizeFunc } from "./
|
|
3
|
-
import { FrontendLocaleData } from "./types";
|
|
2
|
+
import { FrontendLocaleData, LocalizeFunc } from "./types";
|
|
4
3
|
export declare const computeStateDisplay: (localize: LocalizeFunc, stateObj: HassEntity, locale: FrontendLocaleData, state?: string) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function secondsToDuration(d: number): string | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Unit = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
2
|
+
export declare function selectUnit(from: Date | number, to?: Date | number, thresholds?: Partial<Thresholds>): {
|
|
3
|
+
value: number;
|
|
4
|
+
unit: Unit;
|
|
5
|
+
};
|
|
6
|
+
type Thresholds = Record<'second' | 'minute' | 'hour' | 'day', number>;
|
|
7
|
+
export declare const DEFAULT_THRESHOLDS: Thresholds;
|
|
8
|
+
export {};
|
package/dist/get-lovelace.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var intlUtils = require('@formatjs/intl-utils');
|
|
4
|
-
|
|
5
3
|
/**
|
|
6
4
|
* Apply a theme to an element by setting the CSS variables on it.
|
|
7
5
|
*
|
|
@@ -87,6 +85,13 @@ const computeIcon = (stateObj, icon) => {
|
|
|
87
85
|
return DOMAIN_ICONS[domain] || "mdi:bookmark";
|
|
88
86
|
};
|
|
89
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @deprecated Reads `friendly_name`, which Home Assistant is moving away from -
|
|
90
|
+
* it now always includes the device name, so this duplicates context the
|
|
91
|
+
* surrounding UI already shows. Prefer `hass.formatEntityName(stateObj, name)`
|
|
92
|
+
* on HA 2026.4 and later, which resolves the name from the entity's registry
|
|
93
|
+
* context and lets users choose which parts to include.
|
|
94
|
+
*/
|
|
90
95
|
const computeName = (stateObj) => stateObj.attributes.friendly_name || stateObj.entity_id;
|
|
91
96
|
|
|
92
97
|
function computeRTL(hass) {
|
|
@@ -137,6 +142,30 @@ exports.TimeFormat = void 0;
|
|
|
137
142
|
TimeFormat["am_pm"] = "12";
|
|
138
143
|
TimeFormat["twenty_four"] = "24";
|
|
139
144
|
})(exports.TimeFormat || (exports.TimeFormat = {}));
|
|
145
|
+
exports.TimeZone = void 0;
|
|
146
|
+
(function (TimeZone) {
|
|
147
|
+
TimeZone["local"] = "local";
|
|
148
|
+
TimeZone["server"] = "server";
|
|
149
|
+
})(exports.TimeZone || (exports.TimeZone = {}));
|
|
150
|
+
exports.DateFormat = void 0;
|
|
151
|
+
(function (DateFormat) {
|
|
152
|
+
DateFormat["language"] = "language";
|
|
153
|
+
DateFormat["system"] = "system";
|
|
154
|
+
DateFormat["DMY"] = "DMY";
|
|
155
|
+
DateFormat["MDY"] = "MDY";
|
|
156
|
+
DateFormat["YMD"] = "YMD";
|
|
157
|
+
})(exports.DateFormat || (exports.DateFormat = {}));
|
|
158
|
+
exports.FirstWeekday = void 0;
|
|
159
|
+
(function (FirstWeekday) {
|
|
160
|
+
FirstWeekday["language"] = "language";
|
|
161
|
+
FirstWeekday["monday"] = "monday";
|
|
162
|
+
FirstWeekday["tuesday"] = "tuesday";
|
|
163
|
+
FirstWeekday["wednesday"] = "wednesday";
|
|
164
|
+
FirstWeekday["thursday"] = "thursday";
|
|
165
|
+
FirstWeekday["friday"] = "friday";
|
|
166
|
+
FirstWeekday["saturday"] = "saturday";
|
|
167
|
+
FirstWeekday["sunday"] = "sunday";
|
|
168
|
+
})(exports.FirstWeekday || (exports.FirstWeekday = {}));
|
|
140
169
|
|
|
141
170
|
// REF: https://github.com/home-assistant/frontend/blob/dev/src/common/datetime/use_am_pm.ts
|
|
142
171
|
/**
|
|
@@ -735,6 +764,74 @@ function durationToSeconds(duration) {
|
|
|
735
764
|
return parts[0] * 3600 + parts[1] * 60 + parts[2];
|
|
736
765
|
}
|
|
737
766
|
|
|
767
|
+
/*
|
|
768
|
+
* selectUnit() taken from @formatjs/intl-units 3.8.4.
|
|
769
|
+
*
|
|
770
|
+
*/
|
|
771
|
+
const MS_PER_SECOND = 1e3;
|
|
772
|
+
const SECS_PER_MIN = 60;
|
|
773
|
+
const SECS_PER_HOUR = SECS_PER_MIN * 60;
|
|
774
|
+
const SECS_PER_DAY = SECS_PER_HOUR * 24;
|
|
775
|
+
const SECS_PER_WEEK = SECS_PER_DAY * 7;
|
|
776
|
+
function selectUnit(from, to = Date.now(), thresholds = {}) {
|
|
777
|
+
const resolvedThresholds = Object.assign(Object.assign({}, DEFAULT_THRESHOLDS), (thresholds || {}));
|
|
778
|
+
const secs = (+from - +to) / MS_PER_SECOND;
|
|
779
|
+
if (Math.abs(secs) < resolvedThresholds.second) {
|
|
780
|
+
return {
|
|
781
|
+
value: Math.round(secs),
|
|
782
|
+
unit: 'second',
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
const mins = secs / SECS_PER_MIN;
|
|
786
|
+
if (Math.abs(mins) < resolvedThresholds.minute) {
|
|
787
|
+
return {
|
|
788
|
+
value: Math.round(mins),
|
|
789
|
+
unit: 'minute',
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
const hours = secs / SECS_PER_HOUR;
|
|
793
|
+
if (Math.abs(hours) < resolvedThresholds.hour) {
|
|
794
|
+
return {
|
|
795
|
+
value: Math.round(hours),
|
|
796
|
+
unit: 'hour',
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
const days = secs / SECS_PER_DAY;
|
|
800
|
+
if (Math.abs(days) < resolvedThresholds.day) {
|
|
801
|
+
return {
|
|
802
|
+
value: Math.round(days),
|
|
803
|
+
unit: 'day',
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const fromDate = new Date(from);
|
|
807
|
+
const toDate = new Date(to);
|
|
808
|
+
const years = fromDate.getFullYear() - toDate.getFullYear();
|
|
809
|
+
if (Math.round(Math.abs(years)) > 0) {
|
|
810
|
+
return {
|
|
811
|
+
value: Math.round(years),
|
|
812
|
+
unit: 'year',
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
const months = years * 12 + fromDate.getMonth() - toDate.getMonth();
|
|
816
|
+
if (Math.round(Math.abs(months)) > 0) {
|
|
817
|
+
return {
|
|
818
|
+
value: Math.round(months),
|
|
819
|
+
unit: 'month',
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
const weeks = secs / SECS_PER_WEEK;
|
|
823
|
+
return {
|
|
824
|
+
value: Math.round(weeks),
|
|
825
|
+
unit: 'week',
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
const DEFAULT_THRESHOLDS = {
|
|
829
|
+
second: 45, // seconds to minute
|
|
830
|
+
minute: 45, // minutes to hour
|
|
831
|
+
hour: 22, // hour to day
|
|
832
|
+
day: 5, // day to week
|
|
833
|
+
};
|
|
834
|
+
|
|
738
835
|
//REF: https://github.com/home-assistant/frontend/blob/dev/src/common/datetime/relative_time.ts
|
|
739
836
|
const formatRelTimeMem = (locale) => new Intl.RelativeTimeFormat(locale.language, { numeric: "auto" });
|
|
740
837
|
/**
|
|
@@ -743,7 +840,7 @@ const formatRelTimeMem = (locale) => new Intl.RelativeTimeFormat(locale.language
|
|
|
743
840
|
* Example output: 5 minutes ago, in 3 days.
|
|
744
841
|
*/
|
|
745
842
|
const relativeTime = (from, locale, to, includeTense = true) => {
|
|
746
|
-
const diff =
|
|
843
|
+
const diff = selectUnit(from, to);
|
|
747
844
|
if (includeTense) {
|
|
748
845
|
return formatRelTimeMem(locale).format(diff.value, diff.unit);
|
|
749
846
|
}
|
|
@@ -754,6 +851,24 @@ const relativeTime = (from, locale, to, includeTense = true) => {
|
|
|
754
851
|
}).format(Math.abs(diff.value));
|
|
755
852
|
};
|
|
756
853
|
|
|
854
|
+
//REF: https://github.com/home-assistant/frontend/blob/dev/src/common/datetime/seconds_to_duration.ts
|
|
855
|
+
const leftPad = (num) => (num < 10 ? `0${num}` : num);
|
|
856
|
+
function secondsToDuration(d) {
|
|
857
|
+
const h = Math.floor(d / 3600);
|
|
858
|
+
const m = Math.floor((d % 3600) / 60);
|
|
859
|
+
const s = Math.floor((d % 3600) % 60);
|
|
860
|
+
if (h > 0) {
|
|
861
|
+
return `${h}:${leftPad(m)}:${leftPad(s)}`;
|
|
862
|
+
}
|
|
863
|
+
if (m > 0) {
|
|
864
|
+
return `${m}:${leftPad(s)}`;
|
|
865
|
+
}
|
|
866
|
+
if (s > 0) {
|
|
867
|
+
return "" + s;
|
|
868
|
+
}
|
|
869
|
+
return null;
|
|
870
|
+
}
|
|
871
|
+
|
|
757
872
|
function timerTimeRemaining(stateObj) {
|
|
758
873
|
let timeRemaining = durationToSeconds(stateObj.attributes.remaining);
|
|
759
874
|
if (stateObj.state === "active") {
|
|
@@ -1041,18 +1156,15 @@ const formatTimestamp = (timestamp) => {
|
|
|
1041
1156
|
};
|
|
1042
1157
|
|
|
1043
1158
|
const getLovelace = () => {
|
|
1044
|
-
|
|
1045
|
-
root =
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
if (root) {
|
|
1054
|
-
const ll = root.lovelace;
|
|
1055
|
-
ll.current_view = root.___curView;
|
|
1159
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1160
|
+
const root = (_c = (_b = (_a = document
|
|
1161
|
+
.querySelector("home-assistant")) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector("home-assistant-main")) === null || _c === void 0 ? void 0 : _c.shadowRoot;
|
|
1162
|
+
const resolver = (root === null || root === void 0 ? void 0 : root.querySelector("ha-drawer partial-panel-resolver")) ||
|
|
1163
|
+
(root === null || root === void 0 ? void 0 : root.querySelector("app-drawer-layout partial-panel-resolver"));
|
|
1164
|
+
const huiRoot = (_f = (_e = (_d = ((resolver === null || resolver === void 0 ? void 0 : resolver.shadowRoot) || resolver)) === null || _d === void 0 ? void 0 : _d.querySelector("ha-panel-lovelace")) === null || _e === void 0 ? void 0 : _e.shadowRoot) === null || _f === void 0 ? void 0 : _f.querySelector("hui-root");
|
|
1165
|
+
if (huiRoot) {
|
|
1166
|
+
const ll = huiRoot.lovelace;
|
|
1167
|
+
ll.current_view = huiRoot.___curView;
|
|
1056
1168
|
return ll;
|
|
1057
1169
|
}
|
|
1058
1170
|
return null;
|
|
@@ -1090,6 +1202,8 @@ const turnOnOffEntity = (hass, entityId, turnOn = true) => {
|
|
|
1090
1202
|
}
|
|
1091
1203
|
return hass.callService(serviceDomain, service, { entity_id: entityId });
|
|
1092
1204
|
};
|
|
1205
|
+
const turnOnEntity = (hass, entityId) => turnOnOffEntity(hass, entityId, true);
|
|
1206
|
+
const turnOffEntity = (hass, entityId) => turnOnOffEntity(hass, entityId, false);
|
|
1093
1207
|
|
|
1094
1208
|
const toggleEntity = (hass, entityId) => {
|
|
1095
1209
|
const turnOn = STATES_OFF.includes(hass.states[entityId].state);
|
|
@@ -1135,13 +1249,21 @@ const handleActionConfig = (node, hass, config, actionConfig) => {
|
|
|
1135
1249
|
forwardHaptic("success");
|
|
1136
1250
|
}
|
|
1137
1251
|
break;
|
|
1252
|
+
case "turn_on":
|
|
1253
|
+
turnOnOffEntity(hass, actionConfig.entity || config.entity, true);
|
|
1254
|
+
forwardHaptic("success");
|
|
1255
|
+
break;
|
|
1256
|
+
case "turn_off":
|
|
1257
|
+
turnOnOffEntity(hass, actionConfig.entity || config.entity, false);
|
|
1258
|
+
forwardHaptic("success");
|
|
1259
|
+
break;
|
|
1138
1260
|
case "call-service": {
|
|
1139
1261
|
if (!actionConfig.service) {
|
|
1140
1262
|
forwardHaptic("failure");
|
|
1141
1263
|
return;
|
|
1142
1264
|
}
|
|
1143
1265
|
const [domain, service] = actionConfig.service.split(".", 2);
|
|
1144
|
-
hass.callService(domain, service, actionConfig.
|
|
1266
|
+
hass.callService(domain, service, actionConfig.data, actionConfig.target);
|
|
1145
1267
|
forwardHaptic("success");
|
|
1146
1268
|
break;
|
|
1147
1269
|
}
|
|
@@ -1226,7 +1348,7 @@ const handleClick = (node, hass, config, hold, dblClick) => {
|
|
|
1226
1348
|
return;
|
|
1227
1349
|
}
|
|
1228
1350
|
const [domain, service] = actionConfig.service.split(".", 2);
|
|
1229
|
-
const serviceData = Object.assign({}, actionConfig.
|
|
1351
|
+
const serviceData = Object.assign({}, actionConfig.data);
|
|
1230
1352
|
if (serviceData.entity_id === "entity") {
|
|
1231
1353
|
serviceData.entity_id = config.entity;
|
|
1232
1354
|
}
|
|
@@ -1271,6 +1393,46 @@ function hasDoubleClick(config) {
|
|
|
1271
1393
|
return config !== undefined && config.action !== "none";
|
|
1272
1394
|
}
|
|
1273
1395
|
|
|
1396
|
+
/**
|
|
1397
|
+
* Scroll to a specific y coordinate.
|
|
1398
|
+
*
|
|
1399
|
+
* Copied from paper-scroll-header-panel.
|
|
1400
|
+
*
|
|
1401
|
+
* @method scroll
|
|
1402
|
+
* @param {number} top The coordinate to scroll to, along the y-axis.
|
|
1403
|
+
* @param {boolean} smooth true if the scroll position should be smoothly adjusted.
|
|
1404
|
+
*/
|
|
1405
|
+
function scrollToTarget(element, target) {
|
|
1406
|
+
// the scroll event will trigger _updateScrollState directly,
|
|
1407
|
+
// However, _updateScrollState relies on the previous `scrollTop` to update the states.
|
|
1408
|
+
// Calling _updateScrollState will ensure that the states are synced correctly.
|
|
1409
|
+
const top = 0;
|
|
1410
|
+
const scroller = target;
|
|
1411
|
+
const easingFn = function easeOutQuad(t, b, c, d) {
|
|
1412
|
+
/* eslint-disable no-param-reassign, space-infix-ops, no-mixed-operators */
|
|
1413
|
+
t /= d;
|
|
1414
|
+
return -c * t * (t - 2) + b;
|
|
1415
|
+
/* eslint-enable no-param-reassign, space-infix-ops, no-mixed-operators */
|
|
1416
|
+
};
|
|
1417
|
+
const animationId = Math.random();
|
|
1418
|
+
const duration = 200;
|
|
1419
|
+
const startTime = Date.now();
|
|
1420
|
+
const currentScrollTop = scroller.scrollTop;
|
|
1421
|
+
const deltaScrollTop = top - currentScrollTop;
|
|
1422
|
+
element._currentAnimationId = animationId;
|
|
1423
|
+
(function updateFrame() {
|
|
1424
|
+
const now = Date.now();
|
|
1425
|
+
const elapsedTime = now - startTime;
|
|
1426
|
+
if (elapsedTime > duration) {
|
|
1427
|
+
scroller.scrollTop = top;
|
|
1428
|
+
}
|
|
1429
|
+
else if (element._currentAnimationId === animationId) {
|
|
1430
|
+
scroller.scrollTop = easingFn(elapsedTime, currentScrollTop, deltaScrollTop, duration);
|
|
1431
|
+
requestAnimationFrame(updateFrame.bind(element));
|
|
1432
|
+
}
|
|
1433
|
+
}.call(element));
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1274
1436
|
/** Return an icon representing a binary sensor state. */
|
|
1275
1437
|
const binarySensorIcon = (state, stateObj) => {
|
|
1276
1438
|
const is_off = state === "off";
|
|
@@ -1333,17 +1495,86 @@ const coverIcon = (state) => {
|
|
|
1333
1495
|
const open = state.state !== "closed";
|
|
1334
1496
|
switch (state.attributes.device_class) {
|
|
1335
1497
|
case "garage":
|
|
1336
|
-
|
|
1498
|
+
switch (state.state) {
|
|
1499
|
+
case "opening":
|
|
1500
|
+
return "mdi:arrow-up-box";
|
|
1501
|
+
case "closing":
|
|
1502
|
+
return "mdi:arrow-down-box";
|
|
1503
|
+
case "closed":
|
|
1504
|
+
return "mdi:garage";
|
|
1505
|
+
default:
|
|
1506
|
+
return "mdi:garage-open";
|
|
1507
|
+
}
|
|
1508
|
+
case "gate":
|
|
1509
|
+
switch (state.state) {
|
|
1510
|
+
case "opening":
|
|
1511
|
+
case "closing":
|
|
1512
|
+
return "mdi:gate-arrow-right";
|
|
1513
|
+
case "closed":
|
|
1514
|
+
return "mdi:gate";
|
|
1515
|
+
default:
|
|
1516
|
+
return "mdi:gate-open";
|
|
1517
|
+
}
|
|
1337
1518
|
case "door":
|
|
1338
1519
|
return open ? "mdi:door-open" : "mdi:door-closed";
|
|
1520
|
+
case "damper":
|
|
1521
|
+
return open ? "mdi:circle" : "mdi:circle-slice-8";
|
|
1339
1522
|
case "shutter":
|
|
1340
|
-
|
|
1523
|
+
switch (state.state) {
|
|
1524
|
+
case "opening":
|
|
1525
|
+
return "mdi:arrow-up-box";
|
|
1526
|
+
case "closing":
|
|
1527
|
+
return "mdi:arrow-down-box";
|
|
1528
|
+
case "closed":
|
|
1529
|
+
return "mdi:window-shutter";
|
|
1530
|
+
default:
|
|
1531
|
+
return "mdi:window-shutter-open";
|
|
1532
|
+
}
|
|
1533
|
+
case "curtain":
|
|
1534
|
+
switch (state.state) {
|
|
1535
|
+
case "opening":
|
|
1536
|
+
return "mdi:arrow-split-vertical";
|
|
1537
|
+
case "closing":
|
|
1538
|
+
return "mdi:arrow-collapse-horizontal";
|
|
1539
|
+
case "closed":
|
|
1540
|
+
return "mdi:curtains-closed";
|
|
1541
|
+
default:
|
|
1542
|
+
return "mdi:curtains";
|
|
1543
|
+
}
|
|
1341
1544
|
case "blind":
|
|
1342
|
-
|
|
1545
|
+
case "shade":
|
|
1546
|
+
switch (state.state) {
|
|
1547
|
+
case "opening":
|
|
1548
|
+
return "mdi:arrow-up-box";
|
|
1549
|
+
case "closing":
|
|
1550
|
+
return "mdi:arrow-down-box";
|
|
1551
|
+
case "closed":
|
|
1552
|
+
return "mdi:blinds";
|
|
1553
|
+
default:
|
|
1554
|
+
return "mdi:blinds-open";
|
|
1555
|
+
}
|
|
1343
1556
|
case "window":
|
|
1344
|
-
|
|
1557
|
+
switch (state.state) {
|
|
1558
|
+
case "opening":
|
|
1559
|
+
return "mdi:arrow-up-box";
|
|
1560
|
+
case "closing":
|
|
1561
|
+
return "mdi:arrow-down-box";
|
|
1562
|
+
case "closed":
|
|
1563
|
+
return "mdi:window-closed";
|
|
1564
|
+
default:
|
|
1565
|
+
return "mdi:window-open";
|
|
1566
|
+
}
|
|
1345
1567
|
default:
|
|
1346
|
-
|
|
1568
|
+
switch (state.state) {
|
|
1569
|
+
case "opening":
|
|
1570
|
+
return "mdi:arrow-up-box";
|
|
1571
|
+
case "closing":
|
|
1572
|
+
return "mdi:arrow-down-box";
|
|
1573
|
+
case "closed":
|
|
1574
|
+
return "mdi:window-closed";
|
|
1575
|
+
default:
|
|
1576
|
+
return "mdi:window-open";
|
|
1577
|
+
}
|
|
1347
1578
|
}
|
|
1348
1579
|
};
|
|
1349
1580
|
|
|
@@ -1404,7 +1635,7 @@ const inputDateTimeIcon = (state) => {
|
|
|
1404
1635
|
};
|
|
1405
1636
|
|
|
1406
1637
|
const domainIcons = {
|
|
1407
|
-
binary_sensor: binarySensorIcon,
|
|
1638
|
+
binary_sensor: (stateObj) => binarySensorIcon(stateObj.state, stateObj),
|
|
1408
1639
|
cover: coverIcon,
|
|
1409
1640
|
sensor: sensorIcon,
|
|
1410
1641
|
input_datetime: inputDateTimeIcon,
|
|
@@ -1480,6 +1711,7 @@ exports.createThing = createThing;
|
|
|
1480
1711
|
exports.debounce = debounce;
|
|
1481
1712
|
exports.deepEqual = deepEqual;
|
|
1482
1713
|
exports.domainIcon = domainIcon;
|
|
1714
|
+
exports.durationToSeconds = durationToSeconds;
|
|
1483
1715
|
exports.evaluateFilter = evaluateFilter;
|
|
1484
1716
|
exports.fireEvent = fireEvent;
|
|
1485
1717
|
exports.fixedIcons = fixedIcons;
|
|
@@ -1511,9 +1743,13 @@ exports.navigate = navigate;
|
|
|
1511
1743
|
exports.numberFormatToLocale = numberFormatToLocale;
|
|
1512
1744
|
exports.relativeTime = relativeTime;
|
|
1513
1745
|
exports.round = round;
|
|
1746
|
+
exports.scrollToTarget = scrollToTarget;
|
|
1747
|
+
exports.secondsToDuration = secondsToDuration;
|
|
1514
1748
|
exports.stateIcon = stateIcon;
|
|
1515
1749
|
exports.timerTimeRemaining = timerTimeRemaining;
|
|
1516
1750
|
exports.toggleEntity = toggleEntity;
|
|
1751
|
+
exports.turnOffEntity = turnOffEntity;
|
|
1752
|
+
exports.turnOnEntity = turnOnEntity;
|
|
1517
1753
|
exports.turnOnOffEntities = turnOnOffEntities;
|
|
1518
1754
|
exports.turnOnOffEntity = turnOnOffEntity;
|
|
1519
1755
|
//# sourceMappingURL=index.js.map
|