Skip to content
Snippets Groups Projects
Verified Commit 534d55c4 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: new api button #264

parent 7d87df8d
No related branches found
No related tags found
No related merge requests found
Showing
with 1313 additions and 630 deletions
export const projectRoot = "/home/vs/workspaces/oss/monster/monster"; export const projectRoot = "/home/vs/workspaces/oss/monster/monster";
export const sourcePath = "/home/vs/workspaces/oss/monster/monster/source"; export const sourcePath = "/home/vs/workspaces/oss/monster/monster/source";
export const developmentPath = "/home/vs/workspaces/oss/monster/monster/development"; export const developmentPath = "/home/vs/workspaces/oss/monster/monster/development";
export const pnpxBin = "/nix/store/2viji2z5i8ifq0ymhir2z8yyk1g29ddz-pnpm-8.15.5/bin/pnpx"; export const pnpxBin = "/nix/store/z8s3r4vwf4r26g2d7shnw5lva6ihim8f-pnpm-9.15.0/bin/pnpx";
export const nodeBin = "/nix/store/xziigv8xwwr10plxrh8plr5wm0cipf8r-nodejs-22.10.0/bin/node"; export const nodeBin = "/nix/store/hnkyz55vndmvwhg6nzpliv86gh6sxg7h-nodejs-22.10.0/bin/node";
export const license = "/**" + "\n" + export const license = "/**" + "\n" +
" * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved." + "\n" + " * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved." + "\n" +
" * Node module: @schukai/monster" + "\n" + " * Node module: @schukai/monster" + "\n" +
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>new action button bar #264</title>
<script src="./264.mjs" type="module"></script>
</head>
<body>
<h1>new action button bar #264</h1>
<p>similar to action-button</p>
<ul>
<li><a href="https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/264">Issue #264</a></li>
<li><a href="/">Back to overview</a></li>
</ul>
<main>
<!--monster-action-button></monster-action-button -->
<div style="width: 200px">
<monster-api-bar id="tu0Mo"
data-monster-option-url="/issue-264.json"
data-monster-option-mapping-labeltemplate="label"
data-monster-option-mapping-apitemplate="api"
data-monster-option-mapping-urltemplate="url"
><button>sdfsd</button>
</monster-api-bar>
<monster-api-bar id="tu0Mo2"
data-monster-option-url="/issue-264.json"
data-monster-option-mapping-labeltemplate="label"
data-monster-option-mapping-apitemplate="api"
data-monster-option-mapping-urltemplate="url"
data-monster-option-api-body='{"id": "${key}", "name": "monster"}'
>
</monster-api-bar>
</div>
</main>
</body>
</html>
/**
* @file development/issues/open/264.mjs
* @url https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/264
* @description new action button bar
* @issue 264
*/
import "../../../source/components/style/property.pcss";
import "../../../source/components/style/link.pcss";
import "../../../source/components/style/color.pcss";
import "../../../source/components/style/button.pcss";
import "../../../source/components/style/theme.pcss";
import "../../../source/components/style/normalize.pcss";
import "../../../source/components/style/typography.pcss";
import "../../../source/components/form/api-bar.mjs";
const element = document.getElementById('tu0Mo')
/*element.setOption("api.body", {
id: `\${url}`,
name: null,
description: null,
type: null,
})*/
element.fetch()
const json =
`[
{
"id": 10,
"label": "COPY",
"api": "copy",
"url": "/issue-264/action-error"
},
{
"id": 20,
"label": "CUT",
"api": "cut",
"url": "/issue-264/action1?name=CUT"
},
{
"id": 30,
"label": "PASTE",
"api": "paste",
"url": "/issue-264/action1?name=PASTE"
},
{
"id": 40,
"label": "DELETE",
"api": "delete",
"url": "/issue-264/action1?name=DELETE"
},
{
"id": 50,
"label": "RENAME",
"api": "rename",
"url": "/issue-264/action1?name=RENAME"
},
{
"id": 60,
"label": "NEW FOLDER",
"api": "new-folder",
"url": "/issue-264/action1?name=NEW FOLDER"
}
]`;
// check if JSON is valid
JSON.parse(json)
const requestDelay = 10
export default [
{
url: '/issue-264.json',
method: 'get',
rawResponse: async (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.statusCode = 200
const url= new URL(req.url, `http://${req.headers.host}`)
const q = Object.fromEntries(url.searchParams)
if (q && q.q) {
const query = q.q.toLowerCase()
const filtered = JSON.parse(json).filter(item => item.name.toLowerCase().includes(query))
setTimeout(function() {
res.end(JSON.stringify(filtered))
}, requestDelay);
return
}
setTimeout(function() {
res.end(json)
}, requestDelay);
},
},
{
url: '/issue-264/action1',
method: 'post',
response: {
body: `{ "message": "Button 1 clicked" }`,
contentType: 'application/json',
},
},
{
url: '/issue-264/action-error',
method: 'post',
rawResponse: async (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.statusCode = 400
res.end(json)
}
}
];
\ No newline at end of file
...@@ -168,11 +168,11 @@ ...@@ -168,11 +168,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1733808091, "lastModified": 1734083684,
"narHash": "sha256-KWwINTQelKOoQgrXftxoqxmKFZb9pLVfnRvK270nkVk=", "narHash": "sha256-5fNndbndxSx5d+C/D0p/VF32xDiJCJzyOqorOYW4JEo=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a0f3e10d94359665dba45b71b4227b0aeb851f8e", "rev": "314e12ba369ccdb9b352a4db26ff419f7c49fa84",
"type": "github" "type": "github"
}, },
"original": { "original": {
......
...@@ -183,6 +183,8 @@ class DataTable extends CustomElement { ...@@ -183,6 +183,8 @@ class DataTable extends CustomElement {
* @property {boolean} features.footer Footer feature * @property {boolean} features.footer Footer feature
* @property {boolean} features.autoInit Auto init feature (init datasource automatically) * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
* @property {boolean} features.doubleClickCopyToClipboard Double click copy to clipboard feature * @property {boolean} features.doubleClickCopyToClipboard Double click copy to clipboard feature
* @property {boolean} features.copyAll Copy all feature
* @property {boolean} features.help Help feature
* @property {Object} templateMapping Template mapping * @property {Object} templateMapping Template mapping
* @property {string} templateMapping.row-key Row key * @property {string} templateMapping.row-key Row key
* @property {string} templateMapping.filter-id Filter id * @property {string} templateMapping.filter-id Filter id
......
...@@ -1032,6 +1032,12 @@ function collectSearchQueries() { ...@@ -1032,6 +1032,12 @@ function collectSearchQueries() {
* @return {null|Array|undefined|string} * @return {null|Array|undefined|string}
*/ */
function getControlValuesFromLabel(label) { function getControlValuesFromLabel(label) {
// finde das erste Kind-Element vom type input
// wenn es ein input-Element ist, dann @todo
const foundControl = label.firstElementChild; const foundControl = label.firstElementChild;
if (foundControl) { if (foundControl) {
......
...@@ -41,48 +41,15 @@ export { ActionButton }; ...@@ -41,48 +41,15 @@ export { ActionButton };
const containerElementSymbol = Symbol("containerElement"); const containerElementSymbol = Symbol("containerElement");
/** /**
* The ActionButton is a button that opens a popper element with possible actions. * A button that opens a popper element with possible actions.
* *
* <img src="./images/action-button.png"> * @fragments /fragments/components/form/action-button
* *
* You can create this control either by specifying the HTML tag <monster-action-button />` directly in the HTML or using * @example /examples/components/form/action-button
* Javascript via the `document.createElement('monster-action-button');` method.
*
* ```html
* <monster-action-button></monster-action-button>
* ```
*
* Or you can create this CustomControl directly in Javascript:
*
* ```js
* import {PopperButton} from '@schukai/component-form/source/action-button.js';
* document.createElement('monster-action-button');
* ```
*
* @startuml action-button.png
* skinparam monochrome true
* skinparam shadowing false
* HTMLElement <|-- CustomElement
* CustomElement <|-- CustomControl
* CustomControl <|-- Button
* Button <|-- PopperButton
* PopperButton <|-- ActionButton
* @enduml
*
* @copyright schukai GmbH
* @summary A popper button
*/
/**
* A action button control.
*
* @fragments /fragments/components/form/select/
*
* @example /examples/components/form/select-simple
* *
* @since 3.32.0 * @since 3.32.0
* @copyright schukai GmbH * @copyright schukai GmbH
* @summary A ActionButton control * @summary The ActionButton is a button that opens a popper element with possible actions
*/ */
class ActionButton extends PopperButton { class ActionButton extends PopperButton {
/** /**
...@@ -128,7 +95,7 @@ class ActionButton extends PopperButton { ...@@ -128,7 +95,7 @@ class ActionButton extends PopperButton {
/** /**
* *
* @return {Monster.Components.Form.Popper} * @return {ActionButton}
* @fires monster-action-button-show-dialog * @fires monster-action-button-show-dialog
*/ */
showDialog() { showDialog() {
...@@ -141,7 +108,7 @@ class ActionButton extends PopperButton { ...@@ -141,7 +108,7 @@ class ActionButton extends PopperButton {
/** /**
* *
* @return {Monster.Components.Form.Popper} * @return {ActionButton}
*/ */
[assembleMethodSymbol]() { [assembleMethodSymbol]() {
super[assembleMethodSymbol](); super[assembleMethodSymbol]();
...@@ -159,7 +126,7 @@ class ActionButton extends PopperButton { ...@@ -159,7 +126,7 @@ class ActionButton extends PopperButton {
} }
/** /**
* @return {Array<CSSStyleSheet>} * @return {CSSStyleSheet[]}
*/ */
static getCSSStyleSheet() { static getCSSStyleSheet() {
const styles = super.getCSSStyleSheet(); const styles = super.getCSSStyleSheet();
...@@ -205,6 +172,10 @@ function initEventHandler() { ...@@ -205,6 +172,10 @@ function initEventHandler() {
return this; return this;
} }
/**
* @private
* @returns {updateButtonsI18n}
*/
function updateButtonsI18n() { function updateButtonsI18n() {
const translations = getDocumentTranslations(); const translations = getDocumentTranslations();
if (!translations) { if (!translations) {
......
/**
* Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
* Node module: @schukai/monster
*
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
*
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
* For more information about purchasing a commercial license, please contact schukai GmbH.
*/
import {instanceSymbol} from "../../constants.mjs";
import {addAttributeToken} from "../../dom/attributes.mjs";
import {
ATTRIBUTE_ERRORMESSAGE,
ATTRIBUTE_ROLE,
} from "../../dom/constants.mjs";
import {
assembleMethodSymbol,
registerCustomElement,
} from "../../dom/customelement.mjs";
import {isArray, isFunction, isString, isIterable, isObject, isPrimitive} from "../../types/is.mjs";
import {fireCustomEvent} from "../../dom/events.mjs";
import {ButtonBar} from "./button-bar.mjs";
import {validateString} from "../../types/validate.mjs";
import {Pathfinder} from "../../data/pathfinder.mjs";
import {buildMap} from "../../data/buildmap.mjs";
import {ApiButtonStyleSheet} from "./stylesheet/api-button.mjs";
import {Formatter} from "../../text/formatter.mjs";
import {getGlobal} from "../../types/global.mjs";
import "./button.mjs";
import "./message-state-button.mjs";
import "./state-button.mjs";
import {MessageStateButton} from "./message-state-button.mjs";
import {StateButton} from "./state-button.mjs";
export {ApiBar};
/**
* A ApiBar
*
* @fragments /fragments/components/form/api-bar/
*
* @example /examples/components/form/api-bar-simple
*
* @since 3.90.0
* @copyright schukai GmbH
* @summary A beautiful ApiBar that can make your life easier and also looks good.
*/
class ApiBar extends ButtonBar {
/**
* This method is called by the `instanceof` operator.
* @returns {symbol}
*/
static get [instanceSymbol]() {
return Symbol.for("@schukai/monster/components/form/api-bar@@instance");
}
/**
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
*
* The individual configuration values can be found in the table.
*
* @property {object} mapping - The mapping object.
* @property {string} mapping.selector - The selector to find the buttons in the response.
* @property {string} mapping.labelSelector - The selector to find the label for the button.
* @property {string} mapping.labelTemplate - The template to create the label for the button.
* @property {string} mapping.apiTemplate - The key to find the api value in the response.
* @property {string} mapping.urlTemplate - The key to find the url value in the response, if empty the api value is used.
* @property {function} mapping.filter - The filter function to filter the buttons.
* @property {string} url - The url to fetch the data.
* @property {string} buttonTag - The tag name of the button
* @property {object} api - The api options.
* @property {object} api.fetch - The fetch options.
* @property {string} api.body - The body template.
* @property {object} callbacks - The callbacks object.
* @property {function} callbacks.beforeApiCall - The beforeApiCall callback called before the api request is made.
* @property {function} callbacks.failedApiCall - The failedApiCall callback called when the api request failed.
* @property {function} callbacks.successfulApiCall - The successfulApiCall callback called when the api request was successful.
* @property {object} fetch - The fetch options.
* @property {string} fetch.redirect - The redirect option.
* @property {string} fetch.method - The method option.
* @property {string} fetch.mode - The mode option.
* @property {string} fetch.credentials - The credentials option.
* @property {object} fetch.headers - The headers option.
* @property {string} fetch.headers.accept - The acceptance option.
* @property {object} actions - The actions object.
* @property {function} actions.execute - The execute action.
* @property {object} data - The data object, this can be used to store some data and send it with the request.
* @extends {ActionButton.defaults}
*/
get defaults() {
const opts = Object.assign({}, super.defaults, {
mapping: {
selector: "*",
labelSelector: "",
labelTemplate: "",
apiTemplate: "",
urlTemplate: "",
filter: "",
},
api: {
fetch: {
method: "POST",
redirect: "error",
mode: "same-origin",
credentials: "same-origin",
headers: {
accept: "application/json",
},
},
body: null,
},
url: "",
buttonTag: "monster-message-state-button",
callbacks: {
beforeApiCal: null,
failedApiCall: null,
successfulApiCall: null,
},
fetch: {
redirect: "error",
method: "GET",
mode: "same-origin",
credentials: "same-origin",
headers: {
accept: "application/json",
},
},
actions: {
execute: executeAPIButton
},
data: null
});
return opts;
}
/**
*
* @return {Promise}
*/
fetch(url) {
if (url instanceof URL) {
url = url.toString();
}
if (url !== undefined) {
url = validateString(url);
}
return fetchData.call(this, url).then((map) => {
if (
isObject(map) ||
isArray(map) | (map instanceof Set) ||
map instanceof Map
) {
this.importButtons(map);
}
});
}
/**
* Import buttons from a map.
*
* @param {array|object|Map|Set} data
* @return {ApiButton}
* @throws {Error} map is not iterable
* @throws {Error} missing label configuration
*/
importButtons(data) {
const self = this;
const currentButtons = self.querySelectorAll(`[${ATTRIBUTE_ROLE}="api-button"]`);
for (const btnElement of currentButtons) {
btnElement.remove();
}
const mappingOptions = this.getOption("mapping", {});
const selector = mappingOptions?.["selector"];
const labelSelector = mappingOptions?.["labelSelector"];
const labelTemplate = mappingOptions?.["labelTemplate"];
const apiTemplate = mappingOptions?.["apiTemplate"];
let urlTemplate = mappingOptions?.["urlTemplate"];
const filter = mappingOptions?.["filter"];
let flag = false;
let apiEqualUrl = false;
if (labelTemplate === "") {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template");
flag = true;
}
if (apiTemplate === "") {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty api template");
flag = true;
}
if (urlTemplate === "") {
urlTemplate = apiTemplate;
apiEqualUrl = true;
}
if (flag === true) {
throw new Error("missing label or api configuration, check the error attribute");
}
if (isPrimitive(labelSelector) && labelSelector !== "") {
const finder = new Pathfinder(data);
const label = finder.getVia(labelSelector);
this.setOption("labels.button", label);
this.value = label;
}
let labelMap;
const urlMap = buildMap(data, selector, urlTemplate, apiTemplate, filter);
if (apiEqualUrl === true) {
labelMap = urlMap;
} else {
labelMap = buildMap(data, selector, labelTemplate, apiTemplate, filter);
}
const buttons = [];
if (!isIterable(urlMap)) {
throw new Error("map is not iterable");
}
const buttonTag = this.getOption("buttonTag");
const executerCallback = this.getOption("actions.execute");
for (const [iterKey] of urlMap) {
const vmUrl = urlMap.get(iterKey);
const vmLabel = labelMap.get(iterKey);
const button = getGlobal().document.createElement(buttonTag);
button.setAttribute(ATTRIBUTE_ROLE, `api-button`);
button.setOption("labels.button", vmLabel);
button.setOption("actions.click", (event) => {
if (isFunction(executerCallback)) {
executerCallback.call(this, event, {
key: iterKey,
url: vmUrl,
label: vmLabel,
button: button,
})
}
});
this.appendChild(button);
}
try {
this.updateI18n();
} catch (e) {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
}
this.setOption("buttons", buttons);
fireCustomEvent(this, "monster-button-set", {
buttons: buttons,
});
return this;
}
/**
*
* @return {void}
*/
[assembleMethodSymbol]() {
super[assembleMethodSymbol]();
}
/**
* @return {string}
*/
static getTag() {
return "monster-api-bar";
}
/**
* @return {Array<CSSStyleSheet>}
*/
static getCSSStyleSheet() {
const styles = super.getCSSStyleSheet();
styles.push(ApiButtonStyleSheet);
return styles;
}
}
/**
*
* @param {Event} event
* @param {object} opts
*/
function executeAPIButton(event, opts) {
const self = this;
if (!isObject(opts)) {
opts = {};
}
const button = opts?.["button"];
const fetchOptions = self.getOption("api.fetch", {});
const callback = self.getOption("callbacks.beforeApiCall");
if (isFunction(callback)) {
callback.call(self, fetchOptions);
}
const successfulApiCall = self.getOption("callbacks.successfulApiCall");
const failedApiCall = self.getOption("callbacks.failedApiCall");
let url = opts?.["url"];
let label = opts?.["label"];
let key = opts?.["key"];
let body = self.getOption("api.body");
if (isString(body)) {
try {
body = JSON.parse(body);
} catch (e) {
body = {};
}
}
if (isObject(body)) {
const bodyString = JSON.stringify(body);
const obj = {
url: url,
label: label,
key: key,
data: self.getOption("data"),
};
fetchOptions.body = new Formatter(obj, {}).format(bodyString);
}
if (button instanceof HTMLElement) {
button?.setState("activity");
}
fireCustomEvent(self, "monster-api-bar-click", {
button,
});
const global = getGlobal();
global
.fetch(url, fetchOptions)
.then((response) => {
if (!response.ok) {
if (button instanceof MessageStateButton || button instanceof StateButton) {
button.setState("failed", 4000);
}
return Promise.reject(response);
}
const contentType = response?.headers?.get("content-type");
if (contentType && contentType.indexOf("application/json") !== -1) {
return response
.text()
.then((text) => {
try {
const data = JSON.parse(text); // Try to parse the response as JSON
if (button instanceof MessageStateButton || button instanceof StateButton) {
button.setState("successful", 4000);
}
fireCustomEvent(self, "monster-api-bar-successful", {
button,
data,
response,
contentType: response.headers.get("Content-Type"),
});
if (isFunction(successfulApiCall)) {
successfulApiCall.call(self, data, response);
}
} catch (error) {
if (button instanceof HTMLElement) {
button.setState("failed", 4000);
button.setMessage(error.message).showMessage(2000);
}
fireCustomEvent(self, "monster-api-bar-failed", {
button,
error,
response,
contentType: response.headers.get("Content-Type"),
});
}
})
.catch((error) => {
button.setState("failed", 4000);
if (isFunction(failedApiCall)) {
failedApiCall.call(self, error, response);
} else if (button instanceof MessageStateButton || button instanceof StateButton) {
button.setMessage("request failed").showMessage(2000);
}
fireCustomEvent(self, "monster-api-bar-failed", {
button,
error,
response,
contentType: response.headers.get("Content-Type"),
});
});
} else {
return response
.blob()
.then((data) => {
if (button instanceof MessageStateButton || button instanceof StateButton) {
button.setState("successful", 4000);
}
fireCustomEvent(self, "monster-api-bar-successful", {
button,
data,
response,
contentType: response.headers.get("Content-Type"),
});
if (isFunction(successfulApiCall)) {
successfulApiCall.call(self, data, response);
}
})
.catch((error) => {
if (button instanceof MessageStateButton || button instanceof StateButton) {
button.setState("failed", 4000);
}
if (isFunction(failedApiCall)) {
failedApiCall.call(self, error, response);
} else if (button instanceof MessageStateButton || button instanceof StateButton) {
if (error instanceof Response) {
error = new Error(error.statusText);
}
button.setMessage("request failed").showMessage(2000);
}
fireCustomEvent(self, "monster-api-bar-failed", {
button,
error,
response,
contentType: response.headers.get("Content-Type"),
});
});
}
})
.catch((error) => {
if (button instanceof MessageStateButton || button instanceof StateButton) {
button.setState("failed", 4000);
}
if (isFunction(failedApiCall)) {
failedApiCall.call(self, button, error, response);
} else if (button instanceof MessageStateButton || button instanceof StateButton) {
if (error instanceof Response) {
error = new Error(error.statusText);
}
button?.setMessage(error.message).showMessage(3000);
}
fireCustomEvent(self, "monster-api-bar-failed", {
button,
error,
});
});
}
/**
* @private
* @param {string} url
* @return {Promise}
* @throws {TypeError} the result cannot be parsed
* @throws {TypeError} unsupported response
*/
function fetchData(url) {
if (!url) url = this.getOption("url");
if (!url) return Promise.resolve();
const fetchOptions = this.getOption("fetch", {});
const global = getGlobal();
return global
.fetch(url, fetchOptions)
.then((response) => {
const contentType = response.headers.get("content-type");
if (contentType && contentType.indexOf("application/json") !== -1) {
return response.text();
}
throw new TypeError(`unsupported response ${contentType}`);
})
.then((text) => {
try {
return Promise.resolve(JSON.parse(text));
} catch (e) {
throw new TypeError("the result cannot be parsed");
}
});
}
registerCustomElement(ApiBar);
...@@ -210,7 +210,7 @@ class Button extends CustomControl { ...@@ -210,7 +210,7 @@ class Button extends CustomControl {
disabled: false, disabled: false,
actions: { actions: {
click: () => { click: () => {
throw new Error("the click action is not defined");
}, },
}, },
effects: { effects: {
......
...@@ -133,7 +133,7 @@ class FieldSet extends CustomControl { ...@@ -133,7 +133,7 @@ class FieldSet extends CustomControl {
}, },
actions: { actions: {
click: () => { click: () => {
throw new Error("the click action is not defined");
}, },
}, },
value: null, value: null,
......
...@@ -64,7 +64,7 @@ class MessageStateButton extends Popper { ...@@ -64,7 +64,7 @@ class MessageStateButton extends Popper {
* *
* @param {string} state * @param {string} state
* @param {number} timeout * @param {number} timeout
* @return {Monster.Components.Form.MessageStateButton} * @return {MessageStateButton}
* @throws {TypeError} value is not a string * @throws {TypeError} value is not a string
* @throws {TypeError} value is not an instance * @throws {TypeError} value is not an instance
*/ */
...@@ -74,7 +74,7 @@ class MessageStateButton extends Popper { ...@@ -74,7 +74,7 @@ class MessageStateButton extends Popper {
/** /**
* *
* @return {Monster.Components.Form.MessageStateButton} * @return {MessageStateButton}
*/ */
removeState() { removeState() {
return this[buttonElementSymbol].removeState(); return this[buttonElementSymbol].removeState();
...@@ -118,7 +118,7 @@ class MessageStateButton extends Popper { ...@@ -118,7 +118,7 @@ class MessageStateButton extends Popper {
}, },
actions: { actions: {
click: (e) => { click: (e) => {
throw new Error("the click action is not defined");
}, },
}, },
features: { features: {
...@@ -161,7 +161,7 @@ class MessageStateButton extends Popper { ...@@ -161,7 +161,7 @@ class MessageStateButton extends Popper {
* @param {string|HTMLElement}message * @param {string|HTMLElement}message
* @param {string} title * @param {string} title
* @param {string} icon * @param {string} icon
* @return {Monster.Components.Form.MessageStateButton} * @return {MessageStateButton}
*/ */
setMessage(message, title, icon) { setMessage(message, title, icon) {
if (isString(message)) { if (isString(message)) {
...@@ -172,7 +172,7 @@ class MessageStateButton extends Popper { ...@@ -172,7 +172,7 @@ class MessageStateButton extends Popper {
const containerDiv = document.createElement("div"); const containerDiv = document.createElement("div");
const messageDiv = document.createElement("div"); const messageDiv = document.createElement("div");
const titleDiv = document.createElement("div"); const titleDiv = document.createElement("div");
titleDiv.setAttribute("data-monster-role", "message-title-box"); titleDiv.setAttribute(ATTRIBUTE_ROLE, "message-title-box");
let titleElement, iconElement; let titleElement, iconElement;
if (title !== undefined) { if (title !== undefined) {
...@@ -180,7 +180,7 @@ class MessageStateButton extends Popper { ...@@ -180,7 +180,7 @@ class MessageStateButton extends Popper {
titleElement = document.createElement("div"); titleElement = document.createElement("div");
titleElement.setAttribute("class", ""); titleElement.setAttribute("class", "");
titleElement.innerHTML = title; titleElement.innerHTML = title;
titleElement.setAttribute("data-monster-role", "message-title"); titleElement.setAttribute(ATTRIBUTE_ROLE, "message-title");
titleDiv.appendChild(titleElement); titleDiv.appendChild(titleElement);
} }
...@@ -189,7 +189,7 @@ class MessageStateButton extends Popper { ...@@ -189,7 +189,7 @@ class MessageStateButton extends Popper {
iconElement = document.createElement("div"); iconElement = document.createElement("div");
iconElement.setAttribute("class", ""); iconElement.setAttribute("class", "");
iconElement.innerHTML = icon; iconElement.innerHTML = icon;
iconElement.setAttribute("data-monster-role", "message-icon"); iconElement.setAttribute(ATTRIBUTE_ROLE, "message-icon");
titleDiv.appendChild(iconElement); titleDiv.appendChild(iconElement);
} }
...@@ -212,7 +212,7 @@ class MessageStateButton extends Popper { ...@@ -212,7 +212,7 @@ class MessageStateButton extends Popper {
/** /**
* clears the Message * clears the Message
* *
* @return {Monster.Components.Form.MessageStateButton} * @return {MessageStateButton}
*/ */
clearMessage() { clearMessage() {
this.setOption("message.title", undefined); this.setOption("message.title", undefined);
...@@ -254,7 +254,7 @@ class MessageStateButton extends Popper { ...@@ -254,7 +254,7 @@ class MessageStateButton extends Popper {
/** /**
* *
* @return {Monster.Components.Form.MessageStateButton} * @return {MessageStateButton}
*/ */
hideMessage() { hideMessage() {
super.hideDialog(); super.hideDialog();
...@@ -263,7 +263,7 @@ class MessageStateButton extends Popper { ...@@ -263,7 +263,7 @@ class MessageStateButton extends Popper {
/** /**
* *
* @return {Monster.Components.Form.MessageStateButton} * @return {MessageStateButton}
*/ */
toggleMessage() { toggleMessage() {
super.toggleDialog(); super.toggleDialog();
......
...@@ -14,29 +14,23 @@ ...@@ -14,29 +14,23 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
& button {
border: 0;
background: transparent;
width: 100%; width: 100%;
} }
& monster-message-state-button:not(:last-child) { }
border-bottom-color: var(--monster-color-primary-1);
border-bottom-style: var(--monster-border-style);
border-bottom-width: var(--monster-border-width);
& ::part(button) { & monster-message-state-button {
border-bottom-color: var(--monster-color-primary-1); width: auto;
border-bottom-style: var(--monster-border-style); border: 0;
border-bottom-width: var(--monster-border-width);
&::part(button-button) {
border: 0;
margin: 2px;
} }
} }
}
}
} }
...@@ -45,6 +45,11 @@ div[data-monster-role="control"] { ...@@ -45,6 +45,11 @@ div[data-monster-role="control"] {
align-content: center; align-content: center;
justify-content: space-between; justify-content: space-between;
gap: 0.4rem; gap: 0.4rem;
&::slotted(*) {
width: fill-available;
}
} }
......
...@@ -12,4 +12,5 @@ ...@@ -12,4 +12,5 @@
button { button {
width: 100%; width: 100%;
min-width: max-content;
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
[data-monster-role=control] { [data-monster-role=control] {
[data-monster-role=button] { [data-monster-role=button] {
width: 100%; width: 100%;
min-width: max-content ;
} }
} }
......
...@@ -9,6 +9,7 @@ div[data-monster-role="control"] { ...@@ -9,6 +9,7 @@ div[data-monster-role="control"] {
button { button {
width: 100%; width: 100%;
min-width: max-content;
} }
[data-monster-role=button] { [data-monster-role=button] {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment