Compare commits

...
Author SHA1 Message Date
Maarten Lakerveld 3c4edb37df Allow negative number entry on iOS when the number selector has no min
The iOS workaround from #52925 only applied when the selector had an
explicit negative min. The numeric threshold selector used by the power
triggers passes a number selector without a min, so the digit-only keypad
(without a minus key) was still shown. Treat a missing min as allowing
negatives too.

Also leave inputmode unset instead of forcing "text": on a number input
iOS then shows the Numbers and Punctuation keyboard, which has a minus
key and fits numeric entry better than the full QWERTY keyboard.

Fixes #53747
2026-08-28 00:55:06 +02:00
Paulus SchoutsenandGitHub 71d5500ed8 Render camera favorites as camera tiles (#53814) 2026-08-28 00:05:02 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
462321a3c8 Update dependency eslint to v10.9.1 (#53846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-27 22:02:51 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
afc0c36dd9 Update dependency marked to v18.0.11 (#53847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-27 22:02:43 +02:00
7 changed files with 66 additions and 54 deletions
+2 -2
View File
@@ -117,7 +117,7 @@
"lit-html": "3.3.3",
"luxon": "3.7.2",
"maplibre-gl": "5.24.0",
"marked": "18.0.10",
"marked": "18.0.11",
"memoize-one": "6.0.0",
"node-vibrant": "4.0.4",
"object-hash": "3.0.0",
@@ -179,7 +179,7 @@
"browserslist": "4.28.8",
"browserslist-useragent-regexp": "4.1.4",
"del": "8.0.1",
"eslint": "10.9.0",
"eslint": "10.9.1",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-webpack": "0.13.11",
"eslint-plugin-import-x": "4.17.1",
@@ -67,15 +67,16 @@ export class HaNumberSelector extends LitElement {
}
}
// On iOS/iPadOS the numeric and decimal on-screen keypads have no minus key,
// so negatives can only be typed with the full "text" keyboard. Other
// platforms include a minus on their number keypads, so restrict this
// workaround to Safari/WebKit and only when the selector allows negatives
// (e.g. numeric_state triggers/conditions).
const useTextInputMode =
// On iOS/iPadOS the numeric and decimal on-screen keypads have no minus key.
// Leaving inputmode unset on a number input gives the "Numbers and
// Punctuation" keyboard there, which does include a minus. Other platforms
// include a minus on their number keypads, so restrict this workaround to
// Safari/WebKit and only when the selector allows negatives: either an
// explicit negative min, or no min at all (e.g. the numeric threshold
// selector used by the power triggers).
const useSafariNegativeKeyboard =
isSafari &&
this.selector.number?.min !== undefined &&
this.selector.number.min < 0;
(this.selector.number?.min === undefined || this.selector.number.min < 0);
const translationKey = this.selector.number?.translation_key;
let unit = this.selector.number?.unit_of_measurement;
@@ -112,8 +113,8 @@ export class HaNumberSelector extends LitElement {
}
<ha-input
.inputmode=${
useTextInputMode
? "text"
useSafariNegativeKeyboard
? undefined
: this.selector.number?.step === "any" ||
(this.selector.number?.step ?? 1) % 1 !== 0
? "decimal"
@@ -0,0 +1,32 @@
import { computeDomain } from "../../../../common/entity/compute_domain";
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import type {
PictureEntityCardConfig,
TileCardConfig,
} from "../../cards/types";
export const computeFavoriteCardConfig = (
entityId: string
): LovelaceCardConfig => {
// A camera tile would only show a thumbnail, so give the picture the room.
if (computeDomain(entityId) === "camera") {
return {
type: "picture-entity",
entity: entityId,
show_name: false,
show_state: false,
grid_options: {
columns: 6,
rows: 2,
},
} satisfies PictureEntityCardConfig;
}
return {
type: "tile",
entity: entityId,
// Favorites come from all over the home, so name the area.
state_content: ["state", "area_name"],
show_entity_picture: true,
} satisfies TileCardConfig;
};
@@ -34,6 +34,7 @@ import type {
TileCardConfig,
UpdatesCardConfig,
} from "../../cards/types";
import { computeFavoriteCardConfig } from "../helpers/favorite-cards";
import {
LARGE_SCREEN_CONDITION,
SMALL_SCREEN_CONDITION,
@@ -271,15 +272,7 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
column_span: maxColumns,
cards: [
favoritesHeadingCard,
...favoriteEntities.map(
(entityId) =>
({
type: "tile",
entity: entityId,
state_content: ["state", "area_name"],
show_entity_picture: true,
}) satisfies TileCardConfig
),
...favoriteEntities.map(computeFavoriteCardConfig),
],
};
}
@@ -4,8 +4,9 @@ import { isComponentLoaded } from "../../../../common/config/is_component_loaded
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
import { getCommonControlsUsagePrediction } from "../../../../data/usage_prediction";
import type { HomeAssistant } from "../../../../types";
import type { HeadingCardConfig, TileCardConfig } from "../../cards/types";
import type { HeadingCardConfig } from "../../cards/types";
import type { Condition } from "../../common/validate-condition";
import { computeFavoriteCardConfig } from "../helpers/favorite-cards";
import type { LovelaceStrategyDependency } from "../types";
const DEFAULT_LIMIT = 8;
@@ -25,13 +26,6 @@ export interface CommonControlsSectionStrategyConfig {
title_visibilty?: Condition[];
}
const toTileCard = (entity: string): TileCardConfig => ({
type: "tile",
entity,
state_content: ["state", "area_name"],
show_entity_picture: true,
});
@customElement("common-controls-section-strategy")
export class CommonControlsSectionStrategy extends ReactiveElement {
static registryDependencies: readonly LovelaceStrategyDependency[] = [];
@@ -63,7 +57,9 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
// Pinned entities already fill the section, skip the prediction call.
if (includedEntities.length >= limit) {
section.cards!.push(...includedEntities.slice(0, limit).map(toTileCard));
section.cards!.push(
...includedEntities.slice(0, limit).map(computeFavoriteCardConfig)
);
return section;
}
@@ -110,7 +106,7 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
return section;
}
section.cards!.push(...entities.map(toTileCard));
section.cards!.push(...entities.map(computeFavoriteCardConfig));
return section;
}
}
@@ -18,11 +18,9 @@ import type {
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
import type { SecurityAlertEntityConfig } from "../../../data/frontend";
import type { HomeAssistant } from "../../../types";
import type {
LogbookCardConfig,
TileCardConfig,
} from "../../lovelace/cards/types";
import type { LogbookCardConfig } from "../../lovelace/cards/types";
import { computeAreaTileCardConfig } from "../../lovelace/strategies/areas/helpers/areas-strategy-helper";
import { computeFavoriteCardConfig } from "../../lovelace/strategies/helpers/favorite-cards";
import { computeSecurityAlertCardConfig } from "./security-alerts";
export interface SecurityViewStrategyConfig {
@@ -186,15 +184,7 @@ export class SecurityViewStrategy extends ReactiveElement {
),
heading_style: "title",
},
...favoriteEntities.map(
(entityId) =>
({
type: "tile",
entity: entityId,
state_content: ["state", "area_name"],
show_entity_picture: true,
}) satisfies TileCardConfig
),
...favoriteEntities.map(computeFavoriteCardConfig),
],
});
}
+10 -10
View File
@@ -9097,9 +9097,9 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:10.9.0":
version: 10.9.0
resolution: "eslint@npm:10.9.0"
"eslint@npm:10.9.1":
version: 10.9.1
resolution: "eslint@npm:10.9.1"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.8.0"
"@eslint-community/regexpp": "npm:^4.12.2"
@@ -9138,7 +9138,7 @@ __metadata:
optional: true
bin:
eslint: bin/eslint.js
checksum: 10/1cd63bbf4f2c003ed759ab6ae9e2030be0abafdcd7b9ffb5be9e9c3aa3ea6142e6af0a337aac21044957750807fde06c9d052e2c9734cca6792dc2d095f9c180
checksum: 10/4cee237c7d2c445a05330e595b18521d7452fd3f419241bf1ccf81c769a6761c10ca5a06988197482d4842ed1a26b1dcb51b9526408990cee84559e6c08cb3ab
languageName: node
linkType: hard
@@ -10206,7 +10206,7 @@ __metadata:
echarts: "npm:6.1.0"
echarts-extension-chart2music: "npm:0.1.1"
element-internals-polyfill: "npm:3.0.2"
eslint: "npm:10.9.0"
eslint: "npm:10.9.1"
eslint-config-prettier: "npm:10.1.8"
eslint-import-resolver-webpack: "npm:0.13.11"
eslint-plugin-import-x: "npm:4.17.1"
@@ -10246,7 +10246,7 @@ __metadata:
luxon: "npm:3.7.2"
map-stream: "npm:0.0.7"
maplibre-gl: "npm:5.24.0"
marked: "npm:18.0.10"
marked: "npm:18.0.11"
memoize-one: "npm:6.0.0"
minify-literals: "npm:2.2.0"
node-vibrant: "npm:4.0.4"
@@ -11944,12 +11944,12 @@ __metadata:
languageName: node
linkType: hard
"marked@npm:18.0.10":
version: 18.0.10
resolution: "marked@npm:18.0.10"
"marked@npm:18.0.11":
version: 18.0.11
resolution: "marked@npm:18.0.11"
bin:
marked: bin/marked.js
checksum: 10/0d4b560e0773fd6ba30a4e7560ba7ae1f05d47b23926ad8337d9f80c598dfdbffdf2f81e773a1789e8bc9d9c2c2d3d0c9143a54d32581c336a3bbb1bad80461c
checksum: 10/6da69f17820c7442358d751e902d3e0e06fef957e1178d634db938cf339c4504399c9f11a953b0a116b1e5bebc1c7fb52726777cc6c351f2c9f39e4a8276e21a
languageName: node
linkType: hard