UNPKG

timered-counter

Version:

Make the value change more vivid and natural

141 lines 5.58 kB
import { isEmpty, isString } from 'remeda'; import { TimeredCounter } from './timered-counter.js'; import { timeredCounterStringStyles } from './styles/timered-counter-string-styles.js'; import { anyBase } from './utils/any-base.js'; import { graceDefineCustomElement } from './utils/grace-define-custom-element.js'; /** * 替换一些特定的字符. * 1. " ": 空格字符在 HTML 中会被忽略导致无法计算字符宽度, 使用 \xa0 替换. */ const REPLACED_CHARS = { ' ': '\xa0', // &nbsp; }; export class TimeredCounterString extends TimeredCounter { constructor() { super(...arguments); // /** // * 自定义字符集, 传入的 `value` 的字符串表示形式的每个字符都**必须**被包含在该字符集中. // * // * @default `value` 的去重字符集. // */ // @property({ // reflect: true, // }) this.__alphabet = ''; this.__initialValueString = ''; this.__valueString = ''; this.__oldValueString = ''; this.__partsOptions = null; this.__decimalToAnyBase = anyBase(this.stringAdapter, '0123456789', this.__alphabet); this.__anyBaseToDecimal = anyBase(this.stringAdapter, this.__alphabet, '0123456789'); } get initialValue() { return super.initialValue; } set initialValue(value) { if (!isString(value)) { try { value = value.toString(); } catch (error) { throw new Error(`value ${value} is not a string.`); } } this.__initialValueString = value ?? ''; if (isEmpty(this.__initialValueString)) { super.initialValue = this.numberAdapter.create(0); return; } /** * `initialValue` 在初始化时会被赋值给 `oldValue`, 因此, 同步更新逻辑与 `value` 的 setter 一致. */ this.__updateAlphabet(this.__valueString, this.__initialValueString); super.initialValue = this.numberAdapter.create(this.__anyBaseToDecimal(this.__initialValueString)); super.value = this.numberAdapter.create(this.__anyBaseToDecimal(this.__valueString)); } get value() { return super.value; } /** * 通过 property 设置 value 时, 支持任意字符串. */ set value(value) { if (!isString(value)) { try { value = value.toString(); } catch (error) { throw new Error(`value ${value} is not a string.`); } } else if (this.__valueString === value) { return; } this.__oldValueString = this.__valueString; this.__valueString = value ?? ''; if (isEmpty(this.__valueString)) { super.value = this.numberAdapter.create(0); return; } /** * 传入的 value 通过 `__anyBaseToDecimal` 转换为十进制数值, `__anyBaseToDecimal` 则基于 `__alphabet` 计算. * 因此, 当 `__alphabet` 更新时, 需要重新计算 `value` 和 `oldValue` 的值. * 以确保 `value` 和 `oldValue` 能够通过 `__decimalToAnyBase` 转换为原始字符串. */ this.__updateAlphabet(this.__valueString, this.__oldValueString); super.oldValue = this.numberAdapter.create(this.__anyBaseToDecimal(this.__oldValueString)); super.value = this.numberAdapter.create(this.__anyBaseToDecimal(this.__valueString)); } get partsOptions() { return super.partsOptions; } set partsOptions(value) { this.__partsOptions = value; super.partsOptions = { type: 'string', fillChar: REPLACED_CHARS[' '], ...this.__partsOptions, digitToChar: { ' ': REPLACED_CHARS[' '], ...this.__partsOptions.digitToChar, }, }; } /** * 根据 `value`, `initialValue`, `oldValue` 更新字符集. * @private */ __updateAlphabet(value, oldValue) { const allChars = isEmpty(value) && isEmpty(oldValue) ? '' : `\x00${oldValue ?? ''}${value ?? ''}`; const charSet = new Set(this.stringAdapter.stringToChars(allChars)); // if (charSet.size < 10) { // for (let i = 0; i < 10; i++) { // charSet.add(i.toString()); // if (charSet.size >= 10) break; // } // } this.__alphabet = Array.from(charSet).sort().join(''); const sa = this.stringAdapter; const alphabet = this.__alphabet; this.__decimalToAnyBase = anyBase(sa, '0123456789', alphabet); this.__anyBaseToDecimal = anyBase(sa, alphabet, '0123456789'); } sampleToString(value) { return this.__decimalToAnyBase(this.numberAdapter.toString(value)); } connectedCallback() { this.__updateAlphabet(this.__valueString, this.__initialValueString); this.initialValue = this.__initialValueString; this.value = this.__valueString; /** * TimeredCounterString 有自定义的 `fillChar` 和 `digitToChar`. 实例化时需要手动触发 `partsOptions` 的 setter. */ this.partsOptions = this.__partsOptions ?? {}; super.connectedCallback(); } } TimeredCounterString.styles = [...TimeredCounter.styles, timeredCounterStringStyles]; graceDefineCustomElement('timered-counter-string', TimeredCounterString); //# sourceMappingURL=timered-counter-string.js.map