UNPKG

@elf-framework/ui

Version:

ELF - An easy and customizable set of developers

1,749 lines 215 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; var __privateMethod = (obj, member, method) => { __accessCheck(obj, member, "access private method"); return method; }; var _idMap, _items, _parentList, _initialize, initialize_fn, _traverse, traverse_fn; import { isFunction, useMagicMethod, POINTERSTART, isUndefined, isArray, AFTER, UIElement, useState, useCallback, useMemo, classnames, createElementJsx, potal, isString, POINTERENTER, IF, POINTERLEAVE, CLICK, FOCUS, useEffect, Dom, PREVENT, STOP, OBSERVER, PARAMS, POINTEROVER, useRef, isNumber, FOCUSIN, FOCUSOUT, SCROLL, SUBSCRIBE_SELF, DEBOUNCE, FRAME, POINTERMOVE, POINTEREND, debounce, SUBSCRIBE_ALL, pendingComponent, removePendingComponent, useRender } from "@elf-framework/sapa"; import { parse, format, RGBtoHSL, RGBtoHSV, checkHueColor, HSVtoHSL, HSVtoRGB } from "@elf-framework/color"; const style = ""; function usePointerStart(...args) { let [selector, downAction, moveAction, upAction] = args; if (isFunction(selector)) { [downAction, moveAction, upAction] = args; selector = null; } return useMagicMethod(POINTERSTART(selector), (evt) => { if (isFunction(downAction)) { const ret = downAction(evt); if (!isUndefined(ret)) { return ret; } } const move = (e) => { if (isFunction(moveAction)) { moveAction(e); } }; const end = (e) => { if (isFunction(upAction)) upAction(e); document.removeEventListener("mousemove", move); document.removeEventListener("mouseup", end); }; if (isFunction(moveAction)) { document.addEventListener("mousemove", move); } if (isFunction(upAction) || isFunction(moveAction)) { document.addEventListener("mouseup", end); } }); } class BaseTreeViewProvider { get items() { } get ids() { } has(id) { } get(id) { } set(id, obj) { } remove(id) { } setParent(targetId, parentId) { } removeParent(targetId) { } appendChild(parentId, obj) { } getParentId(childId) { } deleteInfo(childObj) { } removeChild(parentId, childId) { } insertChild(targetParentId, targetIndex, currentObject) { } findIndex(list = [], id) { } insertItem(targetId, currentId, type = "before") { } insertBefore(targetId, currentId) { } insertAfter(targetId, currentId) { } insertLast(parentId, childId) { } } class TreeViewProvider extends BaseTreeViewProvider { constructor(items = []) { super(); __privateAdd(this, _initialize); __privateAdd(this, _traverse); __privateAdd(this, _idMap, {}); __privateAdd(this, _items, []); __privateAdd(this, _parentList, {}); __privateSet(this, _items, items); __privateMethod(this, _initialize, initialize_fn).call(this); } get items() { return __privateGet(this, _items); } get ids() { return Object.keys(__privateGet(this, _idMap)); } has(id) { return Boolean(__privateGet(this, _idMap)[id]); } get(id) { return __privateGet(this, _idMap)[id]; } set(id, obj) { const target = this.get(id); if (target) { Object.assign(target, obj); } else { __privateGet(this, _idMap)[id] = obj; } } remove(id) { const obj = __privateGet(this, _idMap)[id]; delete __privateGet(this, _idMap)[id]; return obj; } setParent(targetId, parentId) { __privateGet(this, _parentList)[targetId] = parentId; } removeParent(targetId) { delete __privateGet(this, _parentList)[targetId]; } appendChild(parentId, obj) { const parent = this.get(parentId); if (!parent) return; if (!obj.id) throw new Error("obj.id is required."); if (isArray(parent.children)) { parent.children.push(obj); } else { parent.children = [obj]; } this.set(obj.id, obj); this.setParent(obj.id, parentId); return obj; } getParentId(childId) { return __privateGet(this, _parentList)[childId]; } deleteInfo(childObj) { if (childObj) { this.remove(childObj.id); this.removeParent(childObj.id); return childObj; } } removeChild(parentId, childId) { var _a; const parent = this.get(parentId); const index = this.findIndex(parent.children, childId); if (index < 0) { return; } let childObj; if (parent) { [childObj] = parent.children.splice(index, 1); if (((_a = parent.children) == null ? void 0 : _a.length) === 0) { delete parent.children; } } else { [childObj] = __privateGet(this, _items).splice(index, 1); } return this.deleteInfo(childObj); } insertChild(targetParentId, targetIndex, currentObject) { const targetParent = this.get(targetParentId); this.set(currentObject.id, currentObject); if (targetParent) { targetParent.children.splice(targetIndex, 0, currentObject); this.setParent(currentObject.id, targetParentId); } else { __privateGet(this, _items).splice(targetIndex, 0, currentObject); this.removeParent(currentObject.id); } } findIndex(list = __privateGet(this, _items), id) { return list.findIndex((it) => it.id === id); } insertItem(targetId, currentId, type = "before") { const targetParentId = this.getParentId(targetId); const targetParent = this.get(targetParentId); const targetIndex = this.findIndex(targetParent == null ? void 0 : targetParent.children, targetId); const currentParentId = this.getParentId(currentId); const currentObject = this.removeChild(currentParentId, currentId); this.insertChild( targetParentId, type === "before" ? targetIndex : targetIndex + 1, currentObject ); } insertBefore(targetId, currentId) { return this.insertItem(targetId, currentId, "before"); } insertAfter(targetId, currentId) { return this.insertItem(targetId, currentId, "after"); } insertLast(parentId, childId) { const lastParentId = this.getParentId(childId); const childObj = this.removeChild(lastParentId, childId); if (childObj) { this.appendChild(parentId, childObj); } } } _idMap = new WeakMap(); _items = new WeakMap(); _parentList = new WeakMap(); _initialize = new WeakSet(); initialize_fn = function() { __privateMethod(this, _traverse, traverse_fn).call(this, __privateGet(this, _items)); }; _traverse = new WeakSet(); traverse_fn = function(items = [], parentId) { items.forEach((it) => { var _a; if (__privateGet(this, _idMap)[it.id]) throw new Error("id is duplicated."); __privateGet(this, _idMap)[it.id] = it; __privateGet(this, _parentList)[it.id] = parentId; if ((_a = it.children) == null ? void 0 : _a.length) { __privateMethod(this, _traverse, traverse_fn).call(this, it.children, it.id); } }); }; const NumberStyleKeys = { width: true, height: true, top: true, left: true, right: true, bottom: true, maxWidth: true, maxHeight: true, minWidth: true, minHeight: true, margin: true, marginTop: true, marginRight: true, marginBottom: true, marginLeft: true, padding: true, paddingTop: true, paddingRight: true, paddingBottom: true, paddingLeft: true, border: true, borderTop: true, borderRight: true, borderBottom: true, borderLeft: true, borderWidth: true, borderTopWidth: true, borderRightWidth: true, borderBottomWidth: true, borderLeftWidth: true, gap: true }; const ComponentPropsToStylePropsMap = { alignContent: "alignContent", alignItems: "alignItems", alignSelf: "alignSelf", area: "gridArea", autoColumns: "gridAutoColumns", autoFlow: "gridAutoFlow", autoRows: "gridAutoRows", backgroundColor: "backgroundColor", backgroundImage: "backgroundImage", basis: "flexBasis", border: "border", borderRadius: "borderRadius", bottom: "bottom", boxShadow: "boxShadow", color: "color", column: "gridColumn", columnEnd: "gridColumnEnd", columnGap: "columnGap", columnSpan: "gridColumn", columnStart: "gridColumnStart", direction: "flexDirection", display: "display", flex: "flex", fontFamily: "fontFamily", fontSize: "fontSize", fontStyle: "fontStyle", fontWeight: "fontWeight", gap: "gap", grow: "flexGrow", height: "height", justifyContent: "justifyContent", left: "left", letterSpacing: "letterSpacing", lineHeight: "lineHeight", margin: "margin", marginBlock: "marginBlock", marginBlockEnd: "marginBlockEnd", marginBlockStart: "marginBlockStart", marginBottom: "marginBlockEnd", marginInline: "marginInline", marginInlineEnd: "marginInlineEnd", marginInlineStart: "marginInlineStart", marginLeft: "marginInlineStart", marginRight: "marginInlineEnd", marginTop: "marginBlockStart", maxHeight: "maxHeight", maxWidth: "maxWidth", minHeight: "minHeight", minWidth: "minWidth", objectFit: "objectFit", objectPosition: "objectPosition", opacity: "opacity", order: "order", overflow: "overflow", padding: "padding", paddingBlock: "paddingBlock", paddingBlockEnd: "paddingBlockEnd", paddingBlockStart: "paddingBlockStart", paddingBottom: "paddingBlockEnd", paddingInline: "paddingInline", paddingInlineEnd: "paddingInlineEnd", paddingInlineStart: "paddingInlineStart", paddingLeft: "paddingInlineStart", paddingRight: "paddingInlineEnd", paddingTop: "paddingBlockStart", position: "position", resize: "resize", right: "right", row: "gridRow", rowEnd: "gridRowEnd", rowGap: "rowGap", rowSpan: "gridRow", rowStart: "gridRowStart", shrink: "flexShrink", templateAreas: "gridTemplateAreas", templateColumns: "gridTemplateColumns", templateRows: "gridTemplateRows", textAlign: "textAlign", textDecoration: "textDecoration", textTransform: "textTransform", top: "top", transform: "transform", transformOrigin: "transformOrigin", width: "width", whiteSpace: "whiteSpace", wrap: "flexWrap", zIndex: "zIndex" }; const styleKeys = {}; const uppercasePattern = /([A-Z])/g; const convertStyleKey = (key) => { if (styleKeys[key]) { return styleKeys[key]; } const upperKey = key.replace(uppercasePattern, "-$1").toLowerCase(); styleKeys[key] = upperKey; return upperKey; }; function makeCssVariablePrefixMap(prefix, obj = {}) { const newObj = {}; Object.keys(obj).forEach((key) => { newObj[key] = prefix + "-" + convertStyleKey(key); }); return newObj; } function splitStyleKeyAndNoneStyleKey(properties) { const style2 = {}; const noneStyle = {}; Object.keys(properties).forEach((key) => { const value = properties[key]; const styleKey = ComponentPropsToStylePropsMap[key]; if (styleKey) { style2[styleKey] = value; } else { noneStyle[key] = value; } }); return { style: style2, noneStyle }; } function convertNumberStyleValue(key, value) { if (typeof value === "number") { if (NumberStyleKeys[key]) { value = value + "px"; } } return value; } function propertyMap(styles = {}, mapper = {}) { const styleObj = {}; Object.keys(styles).forEach((key) => { if (typeof styles[key] !== "undefined") { styleObj[mapper[key] || key] = convertNumberStyleValue(key, styles[key]); } }); return Object.keys(styleObj).length ? styleObj : void 0; } const ADD_BODY_FIRST_MOUSEMOVE = "add/body/first/mousemove"; const ADD_BODY_MOUSEMOVE = "add/body/mousemove"; const ADD_BODY_MOUSEUP = "add/body/mouseup"; const BODY_MOVE_EVENT = "body/move/event"; const FIRSTMOVE = (method = "move") => { return AFTER(`bodyMouseFirstMove ${method}`); }; const MOVE = (method = "move") => { return AFTER(`bodyMouseMove ${method}`); }; const END = (method = "end") => { return AFTER(`bodyMouseUp ${method}`); }; const _components = {}; function registerComponent(key, Component) { if (key && Component) { if (_components[key]) { console.warn( `Component ${key} is already registered. Rename key string for `, Component ); } else { _components[key] = Component; } } return Component; } const cssProperties$U = makeCssVariablePrefixMap("--elf--alert", { borderColor: true, backgroundColor: true, selectedBackgroundColor: true, disabledColor: true, color: true, fontSize: true, fontWeight: true, height: true, padding: true, borderRadius: true }); class Alert extends UIElement { template() { const { variant = "default", title = "", content = "", shape = "rect", style: style2 = {}, closable = false, dismissable = false, delay = 0, actions, weak, icon, ...extrProps } = this.props; const [localDelay, setLocalDelay] = useState(delay); const [hide, setHide] = useState(false); this.state.hideCallback = useCallback( (hideDelay = 0) => { setLocalDelay(hideDelay); }, [setLocalDelay] ); const localClass = useMemo(() => { return classnames("elf--alert", { [variant]: true, weak, hide, closable, [shape]: true, dismissable }); }, [variant, weak, hide, closable, shape, dismissable]); const styleObject = { class: localClass, style: { ...propertyMap(style2, cssProperties$U), ...{ transition: `opacity ${localDelay}ms ease-in-out`, opacity: hide ? 0 : 1 } }, ...extrProps }; const titleIcon = title && icon ? icon : void 0; const contentIcon = content && icon && !title ? icon : void 0; const titleActions = title && actions ? actions : void 0; const contentActions = content && actions && !title ? actions : void 0; return /* @__PURE__ */ createElementJsx( "div", { ...styleObject, onContextMenu: (e) => e.preventDefault(), onTransitionEnd: () => { this.props.onHide && this.props.onHide(); this.destroy(true); } }, title ? /* @__PURE__ */ createElementJsx("div", { class: "elf--alert-title" }, titleIcon, " ", /* @__PURE__ */ createElementJsx("span", null, title), " ", titleActions ? /* @__PURE__ */ createElementJsx("div", { class: "elf--alert-actions" }, titleActions) : void 0) : null, content ? /* @__PURE__ */ createElementJsx("div", { class: "elf--alert-content" }, contentIcon, " ", /* @__PURE__ */ createElementJsx("span", null, content), " ", contentActions ? /* @__PURE__ */ createElementJsx("div", { class: "elf--alert-actions" }, contentActions) : void 0) : null, closable ? /* @__PURE__ */ createElementJsx( "div", { class: "elf--alert-close", onClick: () => { setHide(true); if (localDelay === 0) { this.props.onHide && this.props.onHide(); this.destroy(true); } } }, "×" ) : null ); } hide(hideDelay = 0) { var _a; (_a = this.state) == null ? void 0 : _a.hideCallback(hideDelay); } } function alert({ content = void 0, options = {}, ...extraProps }) { return potal(/* @__PURE__ */ createElementJsx(Alert, { ...extraProps }, content), options); } registerComponent("Alert", Alert); registerComponent("alert", Alert); const cssProperties$T = makeCssVariablePrefixMap("--elf--animation", { name: true, iterationCount: true, timingFunction: true, duration: true, delay: true, playState: true }); class Animation extends UIElement { template() { const { name = "spin", delay = "0s", iterationCount, timingFunction, duration = "1s", style: style2 = {}, content, play = false, onEnd: onAnimationEnd, onIteration: onAnimationIteration, onStart: onAnimationStart, onCancel: onAnimationCancel } = this.props; const styleObject = { class: "elf--animation", style: propertyMap( { ...style2, duration, name, iterationCount, timingFunction, delay, playState: play ? "running" : "paused" }, cssProperties$T ), onAnimationStart, onAnimationEnd, onAnimationIteration, onAnimationCancel }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, content); } } Animation.spin = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "spin" }); }; Animation.ping = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "ping" }); }; Animation.fade = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "fade" }); }; Animation.scaledown = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "scaledown" }); }; Animation.bounce = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "bounce" }); }; Animation.flash = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "flash" }); }; Animation.pulse = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "pulse" }); }; Animation.rubberBand = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "rubberBand" }); }; Animation.shake = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "shake" }); }; Animation.headShake = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "headShake" }); }; Animation.swing = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "swing" }); }; Animation.tada = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "tada" }); }; Animation.wobble = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "wobble" }); }; Animation.jello = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "jello" }); }; Animation.heartBeat = function(props) { return /* @__PURE__ */ createElementJsx(Animation, { ...props, name: "heartBeat" }); }; registerComponent("animation", Animation); registerComponent("Animation", Animation); const cssProperties$S = makeCssVariablePrefixMap("--elf--progress-circle", { backgroundColor: true, color: true, duration: true, offset: true, width: true }); class ProgressCircle extends UIElement { template() { const { min = 0, max = 100, value = min, variant = "default", size = "medium", style: style2 = {}, indeterminate = false, animated = false, animationType = "normal" } = this.props; const localClass = useMemo(() => { return classnames("elf--progress-circle", { [variant]: true, [size]: true, animated, indeterminate, [animationType]: true }); }, [variant, size, indeterminate, animated, animationType]); const percentValue = (value - min) / (max - min); const styleObject = { class: localClass, style: propertyMap( { ...style2, offset: percentValue }, cssProperties$S ) }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, /* @__PURE__ */ createElementJsx("div", { class: "progress-area" }, /* @__PURE__ */ createElementJsx("svg", null, /* @__PURE__ */ createElementJsx("circle", { class: "progress-circle track", r: "50%", cx: "50%", cy: "50%" }), /* @__PURE__ */ createElementJsx("circle", { class: "progress-circle fill", r: "50%", cx: "50%", cy: "50%" })))); } } registerComponent("progress-circle", ProgressCircle); registerComponent("progresscircle", ProgressCircle); registerComponent("ProgressCircle", ProgressCircle); const cssProperties$R = makeCssVariablePrefixMap("--elf--button", { borderColor: true, backgroundColor: true, selectedBackgroundColor: true, disabledColor: true, color: true, textColor: true, fontSize: true, fontWeight: true, height: true, padding: true, borderRadius: true }); class Button extends UIElement { template() { const { variant = "default", size = "medium", disabled, selected, focused, shape = "none", quiet = false, outline = false, thin = false, closable = false, place = "", style: style2 = {}, href = "", target = "_blank", content, class: className, iconOnly = false, justified = false, pending = false, play = false, hover = false, as = "button", hasMinWidth = false, ...extraProps } = this.props; const localClass = useMemo(() => { return classnames([ "elf--button", { outline, focused, quiet, selected, closable, justified, [variant]: true, [size]: true, [shape]: true, [place]: true, thin, hover, "icon-only": iconOnly, "has-min-width": hasMinWidth }, className ]); }, [ variant, size, selected, shape, quiet, outline, place, closable, iconOnly, className, justified, focused, hover, hasMinWidth, thin ]); const styleObject = { class: localClass, disabled: disabled ? "disabled" : void 0, style: propertyMap(style2, cssProperties$R), ...extraProps }; const buttonContent = /* @__PURE__ */ createElementJsx("span", null, pending ? /* @__PURE__ */ createElementJsx(Animation.spin, { play }, /* @__PURE__ */ createElementJsx(ProgressCircle, { value: 80, size, variant })) : content || ""); if (as === "link") { return /* @__PURE__ */ createElementJsx("a", { ...styleObject, href, target }, buttonContent); } else { return /* @__PURE__ */ createElementJsx("button", { ...styleObject }, buttonContent); } } } registerComponent("button", Button); registerComponent("btn", Button); registerComponent("Button", Button); const cssProperties$Q = makeCssVariablePrefixMap("--elf--tooltip", { backgroundColor: true, color: true, height: true, hoverColor: true, borderColor: true, boxShadow: true, toolsBorderColor: true, toolsBorderRadius: true, hgap: true, vgap: true, delay: true, contentPadding: true, maxWidth: true, position: true }); const TooltipPlacement = { TOP: "top", BOTTOM: "bottom", LEFT: "left", RIGHT: "right", BOTTOM_LEFT: "bottom-left", BOTTOM_RIGHT: "bottom-right", TOP_LEFT: "top-left", TOP_RIGHT: "top-right" }; class Tooltip extends UIElement { initState() { const trigger = this.props.trigger || "hover"; return { trigger: isString(trigger) ? [trigger] : trigger, delay: 1e3, show: this.props.show || false }; } template() { const { style: style2 = {}, message = "", content, placement = "bottom", animated = false, hideArrow = false, variant = "default", position = "relative", icon } = this.props; const { show } = this.state; const localClass = useMemo(() => { return classnames("elf--tooltip", { [placement]: true, animated, [variant]: true, [position]: true }); }, [placement, animated, variant, position]); const styleObject = { class: localClass, style: propertyMap(style2, cssProperties$Q) }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, /* @__PURE__ */ createElementJsx("div", { class: "content" }, content), show || this.props.show ? /* @__PURE__ */ createElementJsx("div", { class: "message" }, hideArrow ? void 0 : /* @__PURE__ */ createElementJsx("div", { class: "arrow" }), icon ? /* @__PURE__ */ createElementJsx("div", { class: "icon" }, icon) : void 0, /* @__PURE__ */ createElementJsx("div", { class: "message-content" }, /* @__PURE__ */ createElementJsx("div", null, message))) : void 0); } show() { this.open(); } hide() { this.close(); } open() { this.setState({ show: true }); } close() { setTimeout(() => { this.setState({ show: false }); }, this.props.hideDelay); } toggle() { this.setState({ show: !this.state.show }); } checkTriggerClick() { return this.state.trigger.includes("click"); } checkTriggerOver() { return this.state.trigger.includes("hover"); } checkTriggerFocus() { return this.state.trigger.includes("focus"); } [POINTERENTER("$el") + IF("checkTriggerOver")]() { this.open(); } [POINTERLEAVE("$el") + IF("checkTriggerOver")]() { this.close(); } [CLICK("$el") + IF("checkTriggerClick")]() { this.toggle(); } [FOCUS("$el") + IF("checkTriggerFocus")]() { this.open(); } remove() { this.$el.remove(); } } function tooltip({ content, message = "", delay = 0, position = "fixed", placement = "top", options = {}, style: style2, variant = "default" }) { const tooltipInstance = potal( /* @__PURE__ */ createElementJsx( Tooltip, { variant, delay, position, placement, message, style: style2, show: true }, content || /* @__PURE__ */ createElementJsx("span", null, " ") ), options ); return tooltipInstance; } const cssProperties$P = makeCssVariablePrefixMap("--elf--action-group", { alignItems: true, gap: true }); class ActionGroup extends UIElement { template() { const { direction = "horizontal", quiet = false, compact = false, justified = false, collapsed = false, moreIcon = null, boundary = 50, style: style2 = {}, content, shape = "normal", ...extraStyle } = this.props; const [visibleTargetList, setVisibilityTargetList] = useState([]); const [rootRect, setRootRect] = useState(null); const { style: styleProperties } = splitStyleKeyAndNoneStyleKey(extraStyle); useEffect(() => { var _a; if (!collapsed) return; const list = []; let totalWidth = 0; const localRect = (_a = this.$el) == null ? void 0 : _a.rect(); if (!localRect) return; this.$el.children().forEach((child, index) => { if (child.hasClass("hidden-tools")) return; const rect = child.rect(); let isVisible = rect.right + boundary < localRect.right; if (isVisible) { totalWidth += rect.width; if (totalWidth + boundary > localRect.width) { totalWidth = localRect.width - boundary; isVisible = false; } } list[index] = isVisible; }); setVisibilityTargetList(list); }, [collapsed, rootRect]); useEffect(() => { let resizeObserver; if (collapsed) { resizeObserver = new ResizeObserver((entries) => { entries.forEach((entry) => { setRootRect(Dom.create(entry.target).rect()); }); }); if (!this.$el) return; resizeObserver.observe(this.getEl()); } return () => { resizeObserver == null ? void 0 : resizeObserver.disconnect(); }; }, [collapsed]); const localClass = useMemo(() => { return classnames("elf--action-group", { [direction]: true, quiet, compact, collapsed, justified, [shape]: true }); }, [direction, quiet, compact, collapsed, justified, shape]); const styleObject = { class: localClass, style: propertyMap( { ...style2, ...styleProperties }, cssProperties$P ) }; const items = collapsed ? content.filter((item, index) => { return visibleTargetList[index]; }) : content; const hiddenItems = collapsed ? content.filter((item, index) => { return !visibleTargetList[index]; }) : []; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, items, hiddenItems.length ? /* @__PURE__ */ createElementJsx( Tooltip, { message: hiddenItems, trigger: "click", hideArrow: true, position: "bottom-left", style: { contentPadding: "0px" } }, /* @__PURE__ */ createElementJsx(Button, { iconOnly: true }, moreIcon) ) : void 0); } } registerComponent("action-group", ActionGroup); registerComponent("ActionGroup", ActionGroup); function RoundButton({ content, ...props }) { return /* @__PURE__ */ createElementJsx(Button, { ...props, shape: "round" }, content); } function OutlineButton({ content, ...props }) { return /* @__PURE__ */ createElementJsx(Button, { ...props, outline: true }, content); } function IconButton({ content, ...props }) { return /* @__PURE__ */ createElementJsx(RoundButton, { ...props, iconOnly: true }, content); } registerComponent("icon-button", IconButton); registerComponent("iconbutton", IconButton); registerComponent("IconButton", IconButton); const cssProperties$O = makeCssVariablePrefixMap("--elf--link-button", { borderColor: true, backgroundColor: true, disabledColor: true, color: true, fontSize: true, fontWeight: true, padding: true }); class LinkButton extends UIElement { template() { const { disabled, style: style2 = {}, content, onClick, href } = this.props; const styleObject = { class: "elf--link-button", disabled: disabled ? "disabled" : void 0, style: { ...propertyMap(style2, cssProperties$O) } }; return /* @__PURE__ */ createElementJsx("a", { ...styleObject, onClick, href: href || "#" }, /* @__PURE__ */ createElementJsx("span", null, content || "")); } } registerComponent("link-button", LinkButton); registerComponent("linkbutton", LinkButton); registerComponent("LinkButton", LinkButton); const cssProperties$N = makeCssVariablePrefixMap("--elf--radio", { borderColor: true, backgroundColor: true, disabledColor: true, color: true, fontSize: true, fontWeight: true, height: true, padding: true, borderRadius: true }); class Radio extends UIElement { template() { const { disabled, style: style2 = {}, value, content, name, checked = false, onChange, size = "medium", variant = "default" } = this.props; const localClass = useMemo(() => { return classnames([ "elf--radio", { disabled, [size]: true, [variant]: true } ]); }, [disabled, size, variant]); const styleObject = { class: localClass, style: propertyMap(style2, cssProperties$N) }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, /* @__PURE__ */ createElementJsx("label", null, /* @__PURE__ */ createElementJsx( "input", { ref: "$input", type: "radio", ...{ value, name, disabled: disabled ? "disabled" : void 0, checked: checked ? "checked" : void 0 }, onChange: (e) => onChange == null ? void 0 : onChange(e, value) } ), content)); } } registerComponent("radio", Radio); registerComponent("Radio", Radio); const cssProperties$M = makeCssVariablePrefixMap("--elf--radio", { borderColor: true, backgroundColor: true, disabledColor: true, color: true, fontSize: true, fontWeight: true, height: true, padding: true, borderRadius: true }); class RadioGroup extends UIElement { template() { const { disabled, style: style2 = {}, name, value, options = [], onChange, direction = "horizontal", size = "medium", variant = "default" } = this.props; const localClass = useMemo(() => { return classnames("elf--radio-group", { [direction]: true }); }, [direction]); const styleObject = { class: localClass, disabled: disabled ? "disabled" : void 0, style: propertyMap(style2, cssProperties$M) }; const radioName = name || "name-" + this.id; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, options.map((it, index) => { const checked = it.value === value; return /* @__PURE__ */ createElementJsx( Radio, { ref: `$${index}`, name: radioName, value: it.value, onChange: (e, v) => { this.setState({ value: v }, false); onChange(e, v); }, checked, disabled, size, variant }, it.label ); })); } get value() { return this.state.value || this.props.value; } set value(value) { this.setState({ value }); } } registerComponent("RadioGroup", RadioGroup); registerComponent("radio-group", RadioGroup); registerComponent("radiogroup", RadioGroup); const cssProperties$L = { borderColor: "--elf--checkbox-border-color", backgroundColor: "--elf--checkbox-background", disabledColor: "--elf--checkbox-disabled-color", color: "--elf--checkbox-color", fontSize: "--elf--checkbox-font-size", fontWeight: "--elf--checkbox-font-weight", height: "--elf--checkbox-height", padding: "--elf--checkbox-padding", borderRadius: "--elf--checkbox-border-radius" }; class Checkbox extends UIElement { template() { const { disabled, style: style2 = {}, value, content, name, checked = false, onChange, indeterminate = false, variant = "default", size = "medium" } = this.props; const styleObject = { class: classnames([ "elf--checkbox", { disabled, [variant]: true, [size]: true } ]), style: { ...propertyMap(style2, cssProperties$L) } }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, /* @__PURE__ */ createElementJsx("label", null, /* @__PURE__ */ createElementJsx( "input", { ref: "$input", type: "checkbox", ...{ indeterminate, value, name, disabled: disabled ? "disabled" : void 0, checked: checked ? "checked" : void 0 }, onChange: (e) => onChange == null ? void 0 : onChange(e, value) } ), (content == null ? void 0 : content.length) ? /* @__PURE__ */ createElementJsx("span", { class: "text" }, content) : void 0)); } get checked() { return this.refs.$input.checked; } get value() { return this.props.value; } } registerComponent("Checkbox", Checkbox); registerComponent("checkbox", Checkbox); const cssProperties$K = { borderColor: "--elf--checkbox-border-color", backgroundColor: "--elf--checkbox-background", disabledColor: "--elf--checkbox-disabled-color", color: "--elf--checkbox-color", fontSize: "--elf--checkbox-font-size", fontWeight: "--elf--checkbox-font-weight", height: "--elf--checkbox-height", padding: "--elf--checkbox-padding", borderRadius: "--elf--checkbox-border-radius" }; class CheckboxGroup extends UIElement { initState() { return { value: this.props.value || [] }; } template() { const { disabled, style: style2 = {}, value = [], options = [], onChange, direction = "horizontal", size = "medium", variant = "default" } = this.props; const styleObject = { class: classnames([ "elf--checkbox-group", { [direction]: true } ]), disabled: disabled ? "disabled" : void 0, style: { ...propertyMap(style2, cssProperties$K) } }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, options.map((it, index) => { return /* @__PURE__ */ createElementJsx( Checkbox, { ref: `checkbox-${index}`, value: it.value, onChange: (e) => { onChange(e, this.getValues()); }, checked: value == null ? void 0 : value.includes(it.value), disabled, indeterminate: it.indeterminate, size, variant }, it.label ); })); } getValues() { const values = []; Object.keys(this.children).forEach((key) => { const child = this.children[key]; if (child.checked) { values.push(child.value); } }); return values; } get disabled() { return this.props.disabled; } get value() { return this.getValues(); } set value(values = []) { this.setState({ values }); } } registerComponent("checkbox-group", CheckboxGroup); registerComponent("CheckboxGroup", CheckboxGroup); const cssProperties$J = makeCssVariablePrefixMap("--elf--divider", { color: true, margin: true, height: true, borderStyle: true }); class Divider extends UIElement { template() { const { style: style2 = {}, variant = "default", size = "small", margin = "10px", orientation = "horizontal" } = this.props; const localClass = useMemo(() => { return classnames("elf--divider", { [size]: true, [variant]: true, [orientation]: true }); }, [size, variant, orientation]); const styleObject = { class: localClass, style: { ...propertyMap( { ...style2, margin }, cssProperties$J ) } }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, /* @__PURE__ */ createElementJsx("div", { className: "elf--divider-inner" })); } } registerComponent("divider", Divider); registerComponent("Divider", Divider); const MenuItemType = { DIVIDER: "divider", SECTION: "section", MENU: "menu", ITEM: "item", CUSTOM: "custom", LINK: "link" }; function makeMenuItem(items = [], variant, rootClose) { return items.map((it, index) => { const ref = `${it.type || "item"}${index}`; if (isString(it) && it === "-") { return /* @__PURE__ */ createElementJsx(DividerMenuItem, { ref, variant, rootClose }); } else if (isFunction(it)) { return /* @__PURE__ */ createElementJsx( CustomMenuItem, { variant, ref: `custom${index}`, render: it, rootClose } ); } else if (it.type === MenuItemType.CUSTOM) { return /* @__PURE__ */ createElementJsx( CustomMenuItem, { variant, ref, ...it, rootClose } ); } else if (it.type === MenuItemType.LINK) { return /* @__PURE__ */ createElementJsx( LinkMenuItem, { variant, ref, ...it, rootClose } ); } else if (it.type === MenuItemType.SECTION) { return /* @__PURE__ */ createElementJsx( SectionMenuItem, { variant, ref, ...it, rootClose } ); } else if (it.type === MenuItemType.DIVIDER) { return /* @__PURE__ */ createElementJsx( DividerMenuItem, { variant, ref, ...it, rootClose } ); } return /* @__PURE__ */ createElementJsx(MenuItem, { ref, variant, ...it, rootClose }); }); } function DividerMenuItem({ dashed = false }) { return /* @__PURE__ */ createElementJsx("li", { class: "elf--divider", dashed }); } function CustomMenuItem({ render, rootClose }) { return /* @__PURE__ */ createElementJsx("li", { class: "custom" }, render == null ? void 0 : render({ rootClose })); } function LinkMenuItem({ rootClose, title, link }) { return /* @__PURE__ */ createElementJsx("li", { class: "link" }, /* @__PURE__ */ createElementJsx("a", { href: link, onClick: rootClose }, title)); } function SectionMenuItem({ title = "" }) { return /* @__PURE__ */ createElementJsx("li", { class: "section-title" }, title); } class MenuItem extends UIElement { initState() { const { title = "", hover = false, shortcut, icon, items = [], disabled = false, selectable, selected, selectedIcon = "✓", closable = true, rootClose, description, variant } = this.props; return { title, hover, shortcut, icon, items, selectable, selected, selectedIcon, disabled, closable, rootClose, description, variant }; } template() { const { title = "", shortcut, icon, expandIcon = "▶", items = [], hover, selected, selectable, selectedIcon, disabled, rootClose, description, variant, show = false } = this.state; const hasItems = items.length > 0; const selectedValue = isFunction(selected) ? selected() : selected; const localClass = useMemo(() => { return classnames({ hover }); }, [hover]); return /* @__PURE__ */ createElementJsx("li", { class: localClass, disabled: disabled ? true : void 0 }, /* @__PURE__ */ createElementJsx("div", { class: "menu-item-content" }, selectable ? /* @__PURE__ */ createElementJsx("span", { class: "selected-icon" }, selectedValue ? selectedIcon : void 0) : null, icon ? /* @__PURE__ */ createElementJsx("div", { class: "icon" }, icon) : void 0, title ? /* @__PURE__ */ createElementJsx("div", { class: "menu-title" }, title) : void 0, shortcut || hasItems ? /* @__PURE__ */ createElementJsx("div", { class: "value-area" }, shortcut ? /* @__PURE__ */ createElementJsx("div", { class: "shortcut" }, shortcut) : void 0, hasItems ? /* @__PURE__ */ createElementJsx("div", { class: "icon" }, expandIcon) : void 0) : void 0), description ? /* @__PURE__ */ createElementJsx("div", { class: "menu-item-description" }, description) : void 0, items.length > 0 || show ? /* @__PURE__ */ createElementJsx(Menu, { items, variant, rootClose }) : void 0); } checkClickable() { if (this.state.disabled) { return false; } const { type = MenuItemType.ITEM, items = [] } = this.props; return type === MenuItemType.ITEM && items.length === 0; } [CLICK("$el") + IF("checkClickable") + PREVENT + STOP](e) { var _a, _b; const { selectable = false, onClick, closable = true } = this.props; if (selectable) { this.setSelected(!this.selected); } if (isFunction(onClick)) { onClick(e, this); } if (closable) { (_b = (_a = this.props).rootClose) == null ? void 0 : _b.call(_a); } } setSelected(isSelected = false) { this.setState({ selected: isSelected }); } get selected() { return this.state.selected; } } const cssProperties$I = makeCssVariablePrefixMap("--elf--menu", { left: true, top: true, backgroundColor: true, color: true, fontSize: true, fontWeight: true, height: true, padding: true, borderRadius: true, borderColor: true, boxShadow: true, width: true, maxWidth: true, sectionTitleColor: true, sectionTitleBackgroundColor: true, dividerColor: true, directionLeft: true, itemPadding: true }); class Menu extends UIElement { template() { let { style: style2 = {}, type = "menu", x = 0, y = 0, direction = "left", items = [], rootClose, autoPosition = false, variant = "light", compact = false } = this.props; let itemStyle = { ...style2 }; if (x !== 0) itemStyle = { ...itemStyle, left: x }; if (y !== 0) itemStyle = { ...itemStyle, top: y }; if (autoPosition) { const index = items.findIndex((it) => { return it.selectable && it.selected; }); itemStyle = { ...itemStyle, top: -1 * (index * 24 + 8) }; } const localClass = useMemo(() => { return classnames("elf--menu", { [type]: true, [variant]: true, compact }); }, [type, variant, compact]); const styleObject = { "data-direction": direction, class: localClass, style: propertyMap(itemStyle, cssProperties$I) }; return /* @__PURE__ */ createElementJsx("menu", { ...styleObject, onContextMenu: (e) => e.preventDefault() }, makeMenuItem(items, variant, rootClose)); } [OBSERVER("intersection") + PARAMS({ root: document.body })](intersects = []) { const item = intersects.find( (it) => it.isIntersecting && it.intersectionRatio < 1 ); if (item) { const { left: bLeft, right: bRight } = item.boundingClientRect; const { left: iLeft, right: iRight } = item.intersectionRect; let direction = "left"; if (iRight != bRight && iLeft != bLeft) { direction = "center"; } else if (iRight != bRight) { direction = "right"; } this.$el.attr("data-direction", direction); } } } registerComponent("Menu", Menu); registerComponent("MenuItem", MenuItem); registerComponent("SectionMenuItem", SectionMenuItem); registerComponent("DividerMenuItem", DividerMenuItem); registerComponent("menu", Menu); registerComponent("menuitem", MenuItem); registerComponent("sectionmenuitem", SectionMenuItem); registerComponent("dividermenuitem", DividerMenuItem); registerComponent("menu-item", MenuItem); registerComponent("section-menu-item", SectionMenuItem); registerComponent("divider-menu-item", DividerMenuItem); function ArrowIcon() { return /* @__PURE__ */ createElementJsx("svg", { viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ createElementJsx("path", { d: "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" })); } const cssProperties$H = makeCssVariablePrefixMap("--elf--option-menu", { backgroundColor: true, color: true, width: true }); class OptionMenu extends UIElement { template() { const { icon, content, items, quiet, menuStyle = {}, disabled = void 0, autoPosition = false, style: style2 } = this.props; const { isOpen } = this.state; const showMenu = isOpen && items; const localClass = useMemo(() => { return classnames("elf--option-menu", { quiet }); }, [quiet]); const styleObject = { class: localClass, disabled, style: propertyMap(style2, cssProperties$H) }; return /* @__PURE__ */ createElementJsx("div", { ...styleObject }, /* @__PURE__ */ createElementJsx( "div", { class: "content", onClick: () => { this.setState({ isOpen: !this.state.isOpen }); } }, icon ? /* @__PURE__ */ createElementJsx("div", { class: "elf--option-menu-icon" }, icon) : void 0, /* @__PURE__ */ createElementJsx("div", { class: "text" }, content), /* @__PURE__ */ createElementJsx("div", { class: "arrow" }, /* @__PURE__ */ createElementJsx(ArrowIcon, null)) ), showMenu ? /* @__PURE__ */ createElementJsx("div", { class: "menu-area" }, /* @__PURE__ */ createElementJsx( Menu, { type: "dropdown", autoPosition, rootClose: () => { this.close(); }, style: menuStyle, items } )) : void 0); } close() { this.setState({ isOpen: false }); } checkClickable(e) { const $menu = Dom.create(e.target).closest("menu-area"); if ($menu) return false; return true; } checkNotInMenu(e) { const $menu = Dom.create(e.target).closest("elf--option-menu"); if (!$menu) return true; return this.$el.is($menu) === false; } [CLICK("document") + IF("checkClickable") + IF("checkNotInMenu")]() { this.close(); } } registerComponent("OptionMenu", OptionMenu); registerComponent("optionmenu", OptionMenu); registerComponent("option-menu", OptionMenu); const cssProperties$G = makeCssVariablePrefixMap("--elf--dialog", { position: true, backgroundColor: true, color: true, fontSize: true, fontWeight: true, padding: true, borderRadius: true, borderColor: true, boxShadow: true, width: true, height: true }); class Dialog extends UIElement { initState() { const { visible = false, style: style2 = {}, center } = this.props; return { visible, style: style2, center }; } close() { const { onClose } = this.props; if (isFunction(onClose)) { onClose(this); } } ok() { const { onOk } = this.props; if (isFunction(onOk)) { onOk(this); } } cancel() { const { onCancel } = this.props; if (isFunction(onCancel)) { onCancel(this); } } makeDefaultTools() { const { footer, cancelText = "Cancel", okText = "OK", okProps = {}, cancelProps = {} } = this.props; if