Skip to content

Commit

Permalink
Select for sub-buttons, open/close action for pop-up and more...
Browse files Browse the repository at this point in the history
- [x] New feature: Ability to remove the pop-up header
- [x] New feature: Select for sub-buttons
- [x] New feature: Added support for select entities
- [x] New feature: open_action: and close_action: for pop-ups
- [x] Fixed the pop-up preview in the HA 2024.7.x editor for all view types #618
- [x] Issue in preview panel with input_select button #613
  • Loading branch information
Clooos authored Jul 6, 2024
1 parent 13746e1 commit 611a14c
Show file tree
Hide file tree
Showing 15 changed files with 792 additions and 69 deletions.
106 changes: 71 additions & 35 deletions dist/bubble-card.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/bubble-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { handleSeparator } from './cards/separator/index.ts';
import { handleCover } from './cards/cover/index.ts';
import { handleEmptyColumn } from './cards/empty-column/index.ts';
import { handleMediaPlayer } from './cards/media-player/index.ts';
import { handleSelect } from './cards/dropdown/index.ts';
import { handleSelect } from './cards/select/index.ts';
import { createBubbleCardEditor } from './editor/bubble-card-editor.ts';

class BubbleCard extends HTMLElement {
Expand Down
2 changes: 0 additions & 2 deletions src/cards/button/changes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ export function changeIcon(context) {
context.elements.icon.style.display = 'none';
context.elements.image.style.display = 'none';
}

//context.elements.iconContainer.innerHTML = `<ha-state-icon .hass=${context._hass} .stateObj=${context._hass.states[context.config.entity]}></ha-state-icon>`;
}
export function changeName(context) {
const buttonType = getButtonType(context);
Expand Down
19 changes: 12 additions & 7 deletions src/cards/button/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export default `
width: 100%;
height: 50px;
background-color: var(--background-color-2,var(--secondary-background-color));
border-radius: 25px;
mask-image: radial-gradient(white, black);
border-radius: 32px;
overflow: scroll;
/*mask-image: radial-gradient(white, black);*/
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* for Firefox */
-webkit-transform: translateZ(0);
overflow: hidden;
touch-action: pan-y;
}
Expand All @@ -37,6 +39,7 @@ export default `
.bubble-button-background {
background-color: var(--bubble-button-background-color);
opacity: .5;
border-radius: 32px;
}
.bubble-range-fill {
z-index: -1;
Expand All @@ -56,9 +59,9 @@ export default `
}
.bubble-button-card {
overflow: scroll;
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* for Firefox */
// overflow: scroll;
// -ms-overflow-style: none; /* for Internet Explorer, Edge */
// scrollbar-width: none; /* for Firefox */
}
.bubble-button-card::-webkit-scrollbar {
display: none; /* for Chrome, Safari, and Opera */
Expand All @@ -69,6 +72,8 @@ export default `
}
.bubble-range-slider {
cursor: ew-resize;
border-radius: 25px;
overflow: hidden;
}
.bubble-icon-container {
display: flex;
Expand Down Expand Up @@ -165,7 +170,7 @@ export default `
.bubble-sub-button-container {
z-index: 1;
}
@keyframes tap-feedback {
0% {transform: translateX(-100%); opacity: 0;}
64% {transform: translateX(0); opacity: 0.1;}
Expand Down
17 changes: 12 additions & 5 deletions src/cards/pop-up/changes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isColorCloseToWhite } from "../../tools/style.ts";
import { getIcon, getIconColor, getImage, getName, getState, isEntityType, isStateOn, getWeatherIcon } from "../../tools/utils.ts";
import { getIcon, getIconColor, getImage, getName, getState, isEntityType, isStateOn, getWeatherIcon, fireEvent } from "../../tools/utils.ts";
import { getBackdrop } from "./create.ts";
import { addHash, onEditorChange, removeHash } from "./helpers.ts";
import { initializesubButtonIcon } from '../../tools/global-changes.ts';
Expand All @@ -9,12 +9,9 @@ export function changeEditor(context) {

// Fix the empty space caused by the pop-ups in the section view
if (!context.popUp.classList.contains('is-popup-opened') && context.sectionRow.tagName.toLowerCase() === 'hui-card') {
if (!context.editor && !context.sectionRow.hasAttribute("hidden")) {
if (!context.editor && context.editorAccess && !detectedEditor) {
context.sectionRow.toggleAttribute("hidden", true);
context.sectionRow.style.display = "none";
} else if (context.editor && context.sectionRow.hasAttribute("hidden")) {
context.sectionRow.toggleAttribute("hidden", false);
context.sectionRow.style.display = "";
}

// Fix on older Safari versions
Expand All @@ -34,6 +31,8 @@ export function changeEditor(context) {
if (context.editor || detectedEditor !== null) {
context.popUp.classList.add('editor');

context.editorAccess = true;

if (detectedEditor !== null) {
context.elements.popUpContainer?.classList.remove('hidden');
} else {
Expand All @@ -50,6 +49,7 @@ export function changeStyle(context) {
initializesubButtonIcon(context);

const cardLayout = context.config.card_layout;
const showHeader = context.config.show_header ?? true;

if (cardLayout === 'large') {
if (!context.popUp.classList.contains('large')) {
Expand All @@ -70,6 +70,13 @@ export function changeStyle(context) {
context.popUp.classList.remove('rows-2');
}

if (showHeader && context.popUp.classList.contains('no-header')) {
context.popUp.classList.remove('no-header');
} else if (!showHeader && !context.popUp.classList.contains('no-header')){
context.popUp.classList.add('no-header');
}


const state = getState(context);
const { backdropCustomStyle } = getBackdrop(context);

Expand Down
14 changes: 12 additions & 2 deletions src/cards/pop-up/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getBackdrop } from "./create.ts";
import { callAction } from "../../tools/tap-actions.ts";

let popupCount = 0;

Expand Down Expand Up @@ -68,8 +69,13 @@ export function closePopup(context) {
context.verticalStack.removeChild(context.popUp);
}
}, 360);
context.popUp.classList.add('is-popup-closed');

context.popUp.classList.add('is-popup-closed');
context.popUp.classList.remove('is-popup-opened');

if (context.config.close_action) {
callAction(context.popUp, context.config, 'close_action')
}
}
export function openPopup(context) {
if (context.popUp.classList.contains('is-popup-opened')) {
Expand Down Expand Up @@ -116,6 +122,10 @@ export function openPopup(context) {
if (context.config.auto_close > 0) {
context.closeTimeout = setTimeout(removeHash, context.config.auto_close);
}

if (context.config.open_action) {
callAction(context.popUp, context.config, 'open_action')
}
}
export function onUrlChange(context) {
const { hideBackdrop, showBackdrop } = getBackdrop(context);
Expand All @@ -136,7 +146,7 @@ export function onUrlChange(context) {
}
export function onEditorChange(context) {
const { hideBackdrop, showBackdrop } = getBackdrop(context);
const detectedEditor = context.verticalStack.host.closest('hui-card-preview');
const detectedEditor = context.verticalStack.host?.closest('hui-card-preview') || context.verticalStack.host?.closest('hui-card[preview][class]') || context.verticalStack.host?.getRootNode().host?.closest('hui-section[preview][class]');

if (context.editor || detectedEditor !== null) {
hideBackdrop();
Expand Down
10 changes: 10 additions & 0 deletions src/cards/pop-up/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ export default `
-webkit-mask-image: none;
}
.no-header .bubble-header-container {
visibility: hidden !important;
height: 0px !important;
}
.no-header .bubble-pop-up-container {
padding-top: 4px !important;
mask-image: linear-gradient(to bottom, transparent 0px, black 24px, black calc(100% - 24px), transparent 100%) !important;
-webkit-mask-image: linear-gradient(to bottom, transparent 0px, black 24px, black calc(100% - 24px), transparent 100%) !important;
}
.large .bubble-button-card-container {
height: 64px;
border-radius: 32px;
Expand Down
120 changes: 120 additions & 0 deletions src/cards/select/changes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { initializesubButtonIcon } from '../../tools/global-changes.ts';
import {
applyScrollingEffect,
getIcon,
getImage,
getName,
getState,
getAttribute,
getWeatherIcon,
setLayout,
createElement
} from '../../tools/utils.ts';

export function changeIcon(context) {
const icon = getIcon(context);
const image = getImage(context);

if (image !== '') {
context.elements.image.style.backgroundImage = 'url(' + image + ')';
context.elements.icon.style.display = 'none';
context.elements.image.style.display = '';
} else if (icon !== '') {
context.elements.icon.icon = icon;
context.elements.icon.style.color = 'inherit';
context.elements.icon.style.display = '';
context.elements.image.style.display = 'none';
} else {
context.elements.icon.style.display = 'none';
context.elements.image.style.display = 'none';
}
}

export function changeName(context) {
const name = getName(context);
if (name !== context.elements.previousName) {
applyScrollingEffect(context, context.elements.name, name);
context.elements.previousName = name;
}
}

export function changeStatus(context) {
const state = getState(context);

if (state === 'unavailable') {
context.card.classList.add('is-unavailable');
} else {
context.card.classList.remove('is-unavailable');
}
}

export function changeDropdownList(context, elements = context.elements, entity = context.config.entity) {
if (elements.previousEntity === entity) return;

// Append options to the dropdown select element
let options = context._hass.states[entity].attributes.options;
let state = context._hass.states[entity].state;

// Clear the dropdown list
while (elements.dropdownSelect.firstChild) {
elements.dropdownSelect.removeChild(elements.dropdownSelect.firstChild);
}

options.forEach((option, index) => {
const opt = createElement('mwc-list-item');
opt.setAttribute('value', option);
opt.textContent = option;
if (option === state) {
opt.setAttribute('selected', '');
}
elements.dropdownSelect.appendChild(opt);
elements.previousEntity = entity;
});

elements.dropdownContainer.appendChild(elements.dropdownSelect);
}

export function changeStyle(context) {
initializesubButtonIcon(context);
setLayout(context);

const cardLayout = context.config.card_layout;

function addLayoutWhenShadowRootAvailable() {
const mwcMenu = context.elements.dropdownSelect.shadowRoot?.querySelector('mwc-menu');
const mwcMenuShadowRoot = mwcMenu?.shadowRoot;
const mwcMenuSurface = mwcMenuShadowRoot?.querySelector('mwc-menu-surface');
const mwcMenuSurfaceShadowRoot = mwcMenuSurface?.shadowRoot;
const mdcMenuSurface = mwcMenuSurfaceShadowRoot?.querySelector('.mdc-menu-surface');

if (mdcMenuSurface) {
if (cardLayout === 'large' || cardLayout === 'large-2-rows') {
mdcMenuSurface.style.marginTop = '14px';
} else {
mdcMenuSurface.style.marginTop = '';
}
} else {
setTimeout(addLayoutWhenShadowRootAvailable, 0);
}
}

addLayoutWhenShadowRootAvailable();

const state = getState(context);

let customStyle = '';

try {
customStyle = context.config.styles
? Function('hass', 'entityId', 'state', 'icon', 'subButtonIcon', 'getWeatherIcon', 'card', `return \`${context.config.styles}\`;`)
(context._hass, context.config.entity, state, context.elements.icon, context.subButtonIcon, getWeatherIcon, context.card)
: '';
} catch (error) {
console.error('Error in generating select custom templates:', error);
}

if (context.elements.customStyle) {
context.elements.customStyle.innerText = customStyle;
context.elements.dropdownCustomStyleElement.innerText = customStyle;
}
}
Loading

0 comments on commit 611a14c

Please sign in to comment.