UNPKG

uicore-ts

Version:

UICore is a library to build native-like user interfaces using pure Typescript. No HTML is needed at all. Components are described as TS classes and all user interactions are handled explicitly. This library is strongly inspired by the UIKit framework tha

601 lines (600 loc) 22.7 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var UITextView_exports = {}; __export(UITextView_exports, { UITextView: () => UITextView }); module.exports = __toCommonJS(UITextView_exports); var import_UIColor = require("./UIColor"); var import_UIObject = require("./UIObject"); var import_UIRectangle = require("./UIRectangle"); var import_UITextMeasurement = require("./UITextMeasurement"); var import_UIView = require("./UIView"); const _UITextView = class extends import_UIView.UIView { constructor(elementID, textViewType = _UITextView.type.paragraph, viewHTMLElement = null) { const innerElementID = elementID ? `${elementID}_textElement` : void 0; const _textElementView = new import_UIView.UIView(innerElementID, null, textViewType); super(elementID, viewHTMLElement, "span", { _textElementView }); this.attentionIndicatorHTMLString = _UITextView.attentionIndicatorHTMLString; this.textPrefix = ""; this.textSuffix = ""; this._notificationAmount = 0; this._attentionRequired = import_UIObject.NO; this._thousandsSeparator = null; this._textColor = _UITextView.defaultTextColor; this._isSingleLine = import_UIObject.YES; this._automaticFontSizeSelection = import_UIObject.NO; this._fontInvalidationTriggers = { fontSize: "", fontFamily: "", fontWeight: "", fontStyle: "", styleClasses: "" }; this.changesOften = import_UIObject.NO; this._intrinsicHeightCache = new import_UIObject.UIObject(); this._intrinsicWidthCache = new import_UIObject.UIObject(); this.usesVirtualLayoutingForIntrinsicSizing = import_UIObject.NO; this.configureWithObject({ viewHTMLElement: { style: { display: "flex", alignItems: "center", overflow: "hidden" } } }); this.text = ""; this._textElementView = _textElementView; this._textElementView.configureWithObject({ style: { position: "relative", overflow: "hidden", textOverflow: "ellipsis", width: "100%", margin: "0", padding: "0" }, sendControlEventForKey: (0, import_UIObject.EXTEND)(this.sendControlEventForKey.bind(this)) }); this.addSubview(this._textElementView); this.isSingleLine = import_UIObject.YES; this.textColor = this.textColor; this.userInteractionEnabled = import_UIObject.YES; if (textViewType == _UITextView.type.textArea) { this.pausesPointerEvents = import_UIObject.YES; this.addTargetForControlEvent( import_UIView.UIView.controlEvent.PointerUpInside, (sender, event) => sender.focus() ); } } get textElementView() { return this._textElementView; } get containerStyle() { return this.viewHTMLElement.style; } get styleClasses() { return this._textElementView.styleClasses; } set styleClasses(styleClasses) { this._textElementView.styleClasses = styleClasses; } didReceiveBroadcastEvent(event) { super.didReceiveBroadcastEvent(event); } willMoveToSuperview(superview) { super.willMoveToSuperview(superview); } documentFontsDidLoad() { super.documentFontsDidLoad(); this._invalidateFontCache(); this.invalidateMeasurementStrategy(); this._intrinsicHeightCache = new import_UIObject.UIObject(); this._intrinsicWidthCache = new import_UIObject.UIObject(); _UITextView._intrinsicHeightCache = new import_UIObject.UIObject(); _UITextView._intrinsicWidthCache = new import_UIObject.UIObject(); } layoutSubviews() { super.layoutSubviews(); if (this._automaticFontSizeSelection) { this.fontSize = _UITextView.automaticallyCalculatedFontSize( new import_UIRectangle.UIRectangle( 0, 0, this.textElementView.viewHTMLElement.offsetHeight, this.textElementView.viewHTMLElement.offsetWidth ), this.intrinsicContentSize(), this.fontSize, this._minFontSize, this._maxFontSize ); } } _invalidateMeasurementStyles() { this._cachedMeasurementStyles = void 0; import_UITextMeasurement.UITextMeasurement.invalidateElement(this.textElementView.viewHTMLElement); this._intrinsicSizesCache = {}; } _getMeasurementStyles() { if (this._cachedMeasurementStyles) { return this._cachedMeasurementStyles; } if (!this.textElementView.viewHTMLElement.isConnected) { return null; } this.textElementView.viewHTMLElement.offsetHeight; const computed = window.getComputedStyle(this.textElementView.viewHTMLElement); const fontSizeStr = computed.fontSize; const fontSize = parseFloat(fontSizeStr); if (!fontSize || isNaN(fontSize)) { return null; } const lineHeight = this._parseLineHeight(computed.lineHeight, fontSize); if (isNaN(lineHeight)) { return null; } const font = [ computed.fontStyle || "normal", computed.fontVariant || "normal", computed.fontWeight || "normal", fontSize + "px", computed.fontFamily || "sans-serif" ].join(" "); this._cachedMeasurementStyles = { font, fontSize, lineHeight, whiteSpace: computed.whiteSpace || "normal", paddingLeft: parseFloat(computed.paddingLeft) || 0, paddingRight: parseFloat(computed.paddingRight) || 0, paddingTop: parseFloat(computed.paddingTop) || 0, paddingBottom: parseFloat(computed.paddingBottom) || 0, letterSpacing: parseFloat(computed.letterSpacing) || 0, textTransform: computed.textTransform || "none" }; return this._cachedMeasurementStyles; } _parseLineHeight(lineHeight, fontSize) { if (lineHeight === "normal") { return fontSize * 1.2; } if (lineHeight.endsWith("px")) { return parseFloat(lineHeight); } const numericLineHeight = parseFloat(lineHeight); if (!isNaN(numericLineHeight)) { return fontSize * numericLineHeight; } return fontSize * 1.2; } _shouldUseFastMeasurement() { try { const content = this.text || this.textElementView.innerHTML; if (this._innerHTMLKey || this._localizedTextObject) { return import_UIObject.NO; } if (this.notificationAmount > 0) { return import_UIObject.NO; } if (this._attentionRequired) { return import_UIObject.NO; } const hasComplexHTML = /<(?!\/?(b|i|em|strong|span)\b)[^>]+>/i.test(content); if (hasComplexHTML) { return import_UIObject.NO; } const styles = this._getMeasurementStyles(); if (!(styles == null ? void 0 : styles.font)) { return import_UIObject.YES; } const documentHasFont = document.fonts.check(styles.font); if (!documentHasFont) { return import_UIObject.NO; } return import_UIObject.YES; } catch (exception) { console.error(exception); return import_UIObject.NO; } } setUseFastMeasurement(useFast) { this._useFastMeasurement = useFast; this._intrinsicSizesCache = {}; } invalidateMeasurementStrategy() { this._useFastMeasurement = void 0; this._invalidateMeasurementStyles(); } get textAlignment() { return this._textElementView.style.textAlign; } set textAlignment(textAlignment) { this._textAlignment = textAlignment; this._textElementView.style.textAlign = textAlignment; } get textColor() { return this._textColor; } set textColor(color) { this._textColor = color || _UITextView.defaultTextColor; this._textElementView.style.color = this._textColor.stringValue; } get isSingleLine() { return this._isSingleLine; } set isSingleLine(isSingleLine) { this._isSingleLine = isSingleLine; this._intrinsicHeightCache = new import_UIObject.UIObject(); this._intrinsicWidthCache = new import_UIObject.UIObject(); if (isSingleLine) { this._textElementView.style.whiteSpace = "nowrap"; this._textElementView.style.textOverflow = "ellipsis"; this._textElementView.style.display = ""; this._textElementView.style.webkitLineClamp = ""; this._textElementView.style.webkitBoxOrient = ""; return; } this._textElementView.style.whiteSpace = "normal"; this._textElementView.style.textOverflow = "ellipsis"; this._textElementView.style.display = "-webkit-box"; this._textElementView.style.webkitBoxOrient = "vertical"; this.invalidateMeasurementStrategy(); } get notificationAmount() { return this._notificationAmount; } set notificationAmount(notificationAmount) { if (this._notificationAmount == notificationAmount) { return; } this._notificationAmount = notificationAmount; this.text = this.text; this.setNeedsLayoutUpToRootView(); this.notificationAmountDidChange(notificationAmount); } notificationAmountDidChange(notificationAmount) { } get attentionRequired() { return this._attentionRequired; } set attentionRequired(attentionRequired) { if (this._attentionRequired == attentionRequired) { return; } this._attentionRequired = attentionRequired; this.text = this.text; this.setNeedsLayoutUpToRootView(); } get text() { return this._text || this.textElementView.viewHTMLElement.innerHTML; } set text(text) { this._text = text; var notificationText = ""; if (this.notificationAmount) { notificationText = '<span style="color: ' + _UITextView.notificationTextColor.stringValue + ';">' + (" (" + this.notificationAmount + ")").bold() + "</span>"; } var attentionDot = ""; if (this._attentionRequired) { attentionDot = this.attentionIndicatorHTMLString(); } const displayText = this.thousandsSeparator !== null ? _UITextView.applyThousandsSeparatorToNumericalString(text, this.thousandsSeparator) : text; const newInnerHTML = this.textPrefix + (0, import_UIObject.FIRST)(displayText, "") + this.textSuffix + notificationText + attentionDot; if (this.textElementView.viewHTMLElement.innerHTML !== newInnerHTML) { this.textElementView.viewHTMLElement.innerHTML = newInnerHTML; if (this.changesOften) { this._intrinsicHeightCache = new import_UIObject.UIObject(); this._intrinsicWidthCache = new import_UIObject.UIObject(); } this._useFastMeasurement = void 0; this._intrinsicSizesCache = {}; this.invalidateMeasurementStrategy(); this._invalidateMeasurementStyles(); this.clearIntrinsicSizeCache(); this.setNeedsLayout(); } } static applyThousandsSeparatorToNumericalString(value, separator) { const trimmed = (value || "").trim(); if (trimmed === "") { return value; } const parts = trimmed.split("."); const integerPart = parts[0]; const decimalPart = parts.length > 1 ? parts[1] : null; if (!/^-?\d+$/.test(integerPart)) { return value; } const isNegative = integerPart.startsWith("-"); const digits = isNegative ? integerPart.slice(1) : integerPart; let formatted = ""; const offset = digits.length % 3; for (let index = 0; index < digits.length; index++) { if (index > 0 && (index - offset) % 3 === 0) { formatted += separator; } formatted += digits[index]; } const result = (isNegative ? "-" : "") + formatted; return decimalPart !== null ? result + "." + decimalPart : result; } set innerHTML(innerHTML) { this.text = innerHTML; this.invalidateMeasurementStrategy(); } get innerHTML() { return this.viewHTMLElement.innerHTML; } setText(key, defaultString, parameters) { this.textElementView.setInnerHTML(key, defaultString, parameters); this.invalidateMeasurementStrategy(); } get fontSize() { const style = this._textElementView.style.fontSize || window.getComputedStyle(this._textElementView.viewHTMLElement, null).fontSize; const result = parseFloat(style) * _UITextView._pxToPt; return result; } set fontSize(fontSize) { if (fontSize != this.fontSize) { this._textElementView.style.fontSize = "" + fontSize + "pt"; this._intrinsicHeightCache = new import_UIObject.UIObject(); this._intrinsicWidthCache = new import_UIObject.UIObject(); this._invalidateFontCache(); this._invalidateMeasurementStyles(); this.clearIntrinsicSizeCache(); } } useAutomaticFontSize(minFontSize = import_UIObject.nil, maxFontSize = import_UIObject.nil) { this._automaticFontSizeSelection = import_UIObject.YES; this._minFontSize = minFontSize; this._maxFontSize = maxFontSize; this.setNeedsLayout(); } _getFontCacheKey() { const currentTriggers = { fontSize: this._textElementView.style.fontSize || "", fontFamily: this._textElementView.style.fontFamily || "", fontWeight: this._textElementView.style.fontWeight || "", fontStyle: this._textElementView.style.fontStyle || "", styleClasses: this.styleClasses.join(",") }; const hasChanged = currentTriggers.fontSize !== this._fontInvalidationTriggers.fontSize || currentTriggers.fontFamily !== this._fontInvalidationTriggers.fontFamily || currentTriggers.fontWeight !== this._fontInvalidationTriggers.fontWeight || currentTriggers.fontStyle !== this._fontInvalidationTriggers.fontStyle || currentTriggers.styleClasses !== this._fontInvalidationTriggers.styleClasses; if (!this._cachedFontKey || hasChanged) { const computed = this._textElementView.computedStyle; this._cachedFontKey = [ computed.fontStyle, computed.fontVariant, computed.fontWeight, computed.fontSize, computed.fontFamily ].join("_").replace(/[.\s]/g, "_"); this._fontInvalidationTriggers = currentTriggers; } return this._cachedFontKey; } _invalidateFontCache() { this._cachedFontKey = void 0; } static _determinePXAndPTRatios() { if (_UITextView._ptToPx) { return; } const o = document.createElement("div"); o.style.width = "1000pt"; document.body.appendChild(o); _UITextView._ptToPx = o.clientWidth / 1e3; document.body.removeChild(o); _UITextView._pxToPt = 1 / _UITextView._ptToPx; } static automaticallyCalculatedFontSize(bounds, currentSize, currentFontSize, minFontSize, maxFontSize) { minFontSize = (0, import_UIObject.FIRST)(minFontSize, 1); maxFontSize = (0, import_UIObject.FIRST)(maxFontSize, 1e11); const heightMultiplier = bounds.height / (currentSize.height + 1); const widthMultiplier = bounds.width / (currentSize.width + 1); var multiplier = heightMultiplier; if (heightMultiplier > widthMultiplier) { multiplier = widthMultiplier; } const maxFittingFontSize = currentFontSize * multiplier; if (maxFittingFontSize > maxFontSize) { return maxFontSize; } if (minFontSize > maxFittingFontSize) { return minFontSize; } return maxFittingFontSize; } get thousandsSeparator() { return this._thousandsSeparator; } set thousandsSeparator(value) { this._thousandsSeparator = value; } addStyleClass(styleClass) { super.addStyleClass(styleClass); this._invalidateFontCache(); } removeStyleClass(styleClass) { super.removeStyleClass(styleClass); this._invalidateFontCache(); } focus() { this._textElementView.focus(); } blur() { this._textElementView.blur(); } intrinsicContentHeight(constrainingWidth = 0) { var _a; constrainingWidth = Math.max(constrainingWidth.integerValue, 0); const keyPath = (this.textElementView.viewHTMLElement.innerHTML || this.text) + "_csf_" + this._getFontCacheKey() + "." + ("" + constrainingWidth).replace(new RegExp("\\.", "g"), "_"); let cacheObject = _UITextView._intrinsicHeightCache; if (this.changesOften) { cacheObject = this._intrinsicHeightCache; } var result = cacheObject.valueForKeyPath(keyPath); if ((0, import_UIObject.IS_LIKE_NULL)(result)) { const shouldUseFastPath = (_a = this._useFastMeasurement) != null ? _a : this._shouldUseFastMeasurement(); if (shouldUseFastPath) { const styles = this._getMeasurementStyles(); if (styles) { const size = import_UITextMeasurement.UITextMeasurement.calculateTextSize( this.textElementView.viewHTMLElement, (this.text || this.textElementView.innerHTML || "") + "", constrainingWidth || void 0, void 0, styles ); result = size.height; } else { result = super.intrinsicContentHeight(constrainingWidth); } } else { result = super.intrinsicContentHeight(constrainingWidth); } cacheObject.setValueForKeyPath(keyPath, result); } if (isNaN(result) || !result && !this.text) { result = super.intrinsicContentHeight(constrainingWidth); cacheObject.setValueForKeyPath(keyPath, result); } return result; } intrinsicContentWidth(constrainingHeight = 0) { var _a; constrainingHeight = Math.max(constrainingHeight.integerValue, 0); const keyPath = (this.textElementView.viewHTMLElement.innerHTML || this.text) + "_csf_" + this._getFontCacheKey() + "." + ("" + constrainingHeight).replace(new RegExp("\\.", "g"), "_"); let cacheObject = _UITextView._intrinsicWidthCache; if (this.changesOften) { cacheObject = this._intrinsicWidthCache; } var result = cacheObject.valueForKeyPath(keyPath); if ((0, import_UIObject.IS_LIKE_NULL)(result)) { const shouldUseFastPath = (_a = this._useFastMeasurement) != null ? _a : this._shouldUseFastMeasurement(); if (shouldUseFastPath) { const styles = this._getMeasurementStyles(); if (styles) { const size = import_UITextMeasurement.UITextMeasurement.calculateTextSize( this.textElementView.viewHTMLElement, ((this.text || this.textElementView.innerHTML || "") + "").replace(/<br\s*\/?>/gi, "\n"), void 0, constrainingHeight || void 0, styles ); result = size.width; } else { result = super.intrinsicContentWidth(constrainingHeight); } } else { result = super.intrinsicContentWidth(constrainingHeight); } cacheObject.setValueForKeyPath(keyPath, result); } return result; } intrinsicContentSizeWithConstraints(constrainingHeight = 0, constrainingWidth = 0) { const cacheKey = this._getIntrinsicSizeCacheKey(constrainingHeight, constrainingWidth); const cachedResult = this._getCachedIntrinsicSize(cacheKey); if (cachedResult) { return cachedResult; } const result = new import_UIRectangle.UIRectangle(0, 0, 0, 0); if (this.rootView.forceIntrinsicSizeZero) { return result; } let temporarilyInViewTree = import_UIObject.NO; let nodeAboveThisView = null; if (!this.isMemberOfViewTree) { document.body.appendChild(this.viewHTMLElement); temporarilyInViewTree = import_UIObject.YES; nodeAboveThisView = this.viewHTMLElement.nextSibling; } const height = this._textElementView.style.height; const width = this._textElementView.style.width; this._textElementView.style.height = "" + constrainingHeight + "px"; this._textElementView.style.width = "" + constrainingWidth + "px"; const left = this._textElementView.style.left; const right = this._textElementView.style.right; const bottom = this._textElementView.style.bottom; const top = this._textElementView.style.top; this._textElementView.style.left = ""; this._textElementView.style.right = ""; this._textElementView.style.bottom = ""; this._textElementView.style.top = ""; const resultHeight = this._textElementView.viewHTMLElement.scrollHeight; const whiteSpace = this._textElementView.style.whiteSpace; this._textElementView.style.whiteSpace = "nowrap"; const resultWidth = this._textElementView.viewHTMLElement.scrollWidth; this._textElementView.style.whiteSpace = whiteSpace; this._textElementView.style.height = height; this._textElementView.style.width = width; this._textElementView.style.left = left; this._textElementView.style.right = right; this._textElementView.style.bottom = bottom; this._textElementView.style.top = top; if (temporarilyInViewTree) { document.body.removeChild(this.viewHTMLElement); if (this.superview) { if (nodeAboveThisView) { this.superview.viewHTMLElement.insertBefore(this.viewHTMLElement, nodeAboveThisView); } else { this.superview.viewHTMLElement.appendChild(this.viewHTMLElement); } } } result.height = resultHeight; result.width = resultWidth; this._setCachedIntrinsicSize(cacheKey, result); return result; } }; let UITextView = _UITextView; UITextView.defaultTextColor = import_UIColor.UIColor.blackColor; UITextView.notificationTextColor = import_UIColor.UIColor.redColor; UITextView.attentionRequiredColor = new import_UIColor.UIColor("#f59e0b"); UITextView.attentionIndicatorHTMLString = () => '<span style="color: ' + _UITextView.attentionRequiredColor.stringValue + '; margin-left: 4px;">\u25CF</span>'; UITextView._intrinsicHeightCache = new import_UIObject.UIObject(); UITextView._intrinsicWidthCache = new import_UIObject.UIObject(); UITextView.type = { "paragraph": "p", "header1": "h1", "header2": "h2", "header3": "h3", "header4": "h4", "header5": "h5", "header6": "h6", "textArea": "textarea", "textField": "input", "span": "span", "label": "label" }; UITextView.textAlignment = { "left": "left", "center": "center", "right": "right", "justify": "justify" }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { UITextView }); //# sourceMappingURL=UITextView.js.map