timered-counter 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,8 +30,8 @@ export declare class CounterAdapter {
30
30
  * @protected
31
31
  */
32
32
  static VALUE_CONVERTER: {
33
- fromAttribute(value: string | null): any;
34
- toAttribute(value: unknown): string;
33
+ fromAttribute(value: string | null): string | null;
34
+ toAttribute(value: unknown): string | null | undefined;
35
35
  };
36
36
  static setNumberAdapter(adapterOrType: NumberAdapter | 'number' | 'decimal.js', config?: Decimal.Config): void;
37
37
  static setStringAdapter(adapterOrType: StringAdapter | 'string' | 'intl-segmenter' | 'grapheme-splitter'): void;
@@ -60,10 +60,12 @@ CounterAdapter.STRING_ADAPTER = BuildInStringAdapter();
60
60
  */
61
61
  CounterAdapter.VALUE_CONVERTER = {
62
62
  fromAttribute(value) {
63
- return CounterAdapter.NUMBER_ADAPTER.create(isNullish(value) ? 0 : value);
63
+ return value;
64
64
  },
65
65
  toAttribute(value) {
66
- return CounterAdapter.NUMBER_ADAPTER.toString(value);
66
+ return isNullish(value)
67
+ ? value
68
+ : CounterAdapter.NUMBER_ADAPTER.toString(value);
67
69
  },
68
70
  };
69
71
  //# sourceMappingURL=counter-adapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"counter-adapter.js","sourceRoot":"","sources":["../../src/counter-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,EACL,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,uBAAuB,GAExB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,OAAO,cAAc;IAuCzB,MAAM,CAAC,gBAAgB,CACrB,aAAsD,EACtD,MAAuB;QAEvB,IAAI,OAAO,GAAkB,oBAAoB,EAAE,CAAC;QAEpD,IAAI,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5B,IAAI,aAAa,KAAK,QAAQ;gBAAE,OAAO,GAAG,oBAAoB,EAAE,CAAC;iBAC5D,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAC1D,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,aAAa,CAAC;QAC1B,CAAC;QAED,cAAc,CAAC,cAAc,GAAG,OAAO,CAAC;IAC1C,CAAC;IAED,MAAM,CAAC,gBAAgB,CACrB,aAIuB;QAEvB,IAAI,OAAO,GAAkB,oBAAoB,EAAE,CAAC;QAEpD,IAAI,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5B,IAAI,aAAa,KAAK,QAAQ;gBAAE,OAAO,GAAG,oBAAoB,EAAE,CAAC;iBAC5D,IAAI,aAAa,KAAK,gBAAgB;gBACzC,OAAO,GAAG,2BAA2B,EAAE,CAAC;iBACrC,IAAI,aAAa,KAAK,mBAAmB;gBAC5C,OAAO,GAAG,uBAAuB,EAAE,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,aAAa,CAAC;QAC1B,CAAC;QAED,cAAc,CAAC,cAAc,GAAG,OAAO,CAAC;IAC1C,CAAC;;AA3ED;;;;;;;;GAQG;AACI,6BAAc,GAAkB,oBAAoB,EAAE,CAAC;AAE9D;;;;;;;;;GASG;AACI,6BAAc,GAAkB,oBAAoB,EAAE,CAAC;AAE9D;;;;;GAKG;AACI,8BAAe,GAAG;IACvB,aAAa,CAAC,KAAoB;QAChC,OAAO,cAAc,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC5E,CAAC;IACD,WAAW,CAAC,KAAc;QACxB,OAAO,cAAc,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;CACF,CAAC","sourcesContent":["import { isNullish, isString } from 'remeda';\nimport { Decimal } from 'decimal.js';\nimport {\n BuildInNumberAdapter,\n DecimalJsAdapter,\n NumberAdapter,\n} from './number-adapter/index.js';\nimport {\n BuildInIntlSegmenterAdapter,\n BuildInStringAdapter,\n GraphemeSplitterAdapter,\n StringAdapter,\n} from './string-adapter/index.js';\n\nexport class CounterAdapter {\n /**\n * 数字适配器, 有以下两种:\n * 1. BuildInNumberAdapter(默认): 使用内置 number 进行计算.\n * 2. DecimalJsAdapter: 使用 Decimal.js 进行计算.\n *\n * 详细信息请查看[字符长度限制](/guide/optional-dependencies#字符长度限制)章节.\n *\n * @default BuildInNumberAdapter\n */\n static NUMBER_ADAPTER: NumberAdapter = BuildInNumberAdapter();\n\n /**\n * 字符串适配器, 有以下两种:\n * 1. BuildInStringAdapter(默认): 使用内置 string 进行字符串处理.\n * 2. BuildInIntlSegmenterAdapter: 使用 Intl.Segmenter 进行字符串处理. 能够支持 emoji, 字符集.\n * 3. GraphemeSplitterAdapter: 使用 grapheme-splitter 进行字符串处理. 能够支持 emoji, 字符集.\n *\n * 详细信息请查看[支持 emoji 分词](/guide/optional-dependencies#支持-emoji-分词)章节.\n *\n * @default BuildInStringAdapter\n */\n static STRING_ADAPTER: StringAdapter = BuildInStringAdapter();\n\n /**\n * 将 value 及其相关的属性, 在 attribute 和 property 上的互相转换.\n *\n * @see https://lit.dev/docs/components/properties/#attributes\n * @protected\n */\n static VALUE_CONVERTER = {\n fromAttribute(value: string | null) {\n return CounterAdapter.NUMBER_ADAPTER.create(isNullish(value) ? 0 : value);\n },\n toAttribute(value: unknown) {\n return CounterAdapter.NUMBER_ADAPTER.toString(value);\n },\n };\n\n static setNumberAdapter(\n adapterOrType: NumberAdapter | 'number' | 'decimal.js',\n config?: Decimal.Config,\n ) {\n let adapter: NumberAdapter = BuildInNumberAdapter();\n\n if (isString(adapterOrType)) {\n if (adapterOrType === 'number') adapter = BuildInNumberAdapter();\n else if (['decimal.js', 'decimaljs'].includes(adapterOrType))\n adapter = DecimalJsAdapter(config);\n } else {\n adapter = adapterOrType;\n }\n\n CounterAdapter.NUMBER_ADAPTER = adapter;\n }\n\n static setStringAdapter(\n adapterOrType:\n | StringAdapter\n | 'string'\n | 'intl-segmenter'\n | 'grapheme-splitter',\n ) {\n let adapter: StringAdapter = BuildInStringAdapter();\n\n if (isString(adapterOrType)) {\n if (adapterOrType === 'string') adapter = BuildInStringAdapter();\n else if (adapterOrType === 'intl-segmenter')\n adapter = BuildInIntlSegmenterAdapter();\n else if (adapterOrType === 'grapheme-splitter')\n adapter = GraphemeSplitterAdapter();\n } else {\n adapter = adapterOrType;\n }\n\n CounterAdapter.STRING_ADAPTER = adapter;\n }\n}\n"]}
1
+ {"version":3,"file":"counter-adapter.js","sourceRoot":"","sources":["../../src/counter-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,EACL,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,uBAAuB,GAExB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,OAAO,cAAc;IAyCzB,MAAM,CAAC,gBAAgB,CACrB,aAAsD,EACtD,MAAuB;QAEvB,IAAI,OAAO,GAAkB,oBAAoB,EAAE,CAAC;QAEpD,IAAI,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5B,IAAI,aAAa,KAAK,QAAQ;gBAAE,OAAO,GAAG,oBAAoB,EAAE,CAAC;iBAC5D,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAC1D,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,aAAa,CAAC;QAC1B,CAAC;QAED,cAAc,CAAC,cAAc,GAAG,OAAO,CAAC;IAC1C,CAAC;IAED,MAAM,CAAC,gBAAgB,CACrB,aAIuB;QAEvB,IAAI,OAAO,GAAkB,oBAAoB,EAAE,CAAC;QAEpD,IAAI,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5B,IAAI,aAAa,KAAK,QAAQ;gBAAE,OAAO,GAAG,oBAAoB,EAAE,CAAC;iBAC5D,IAAI,aAAa,KAAK,gBAAgB;gBACzC,OAAO,GAAG,2BAA2B,EAAE,CAAC;iBACrC,IAAI,aAAa,KAAK,mBAAmB;gBAC5C,OAAO,GAAG,uBAAuB,EAAE,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,aAAa,CAAC;QAC1B,CAAC;QAED,cAAc,CAAC,cAAc,GAAG,OAAO,CAAC;IAC1C,CAAC;;AA7ED;;;;;;;;GAQG;AACI,6BAAc,GAAkB,oBAAoB,EAAE,CAAC;AAE9D;;;;;;;;;GASG;AACI,6BAAc,GAAkB,oBAAoB,EAAE,CAAC;AAE9D;;;;;GAKG;AACI,8BAAe,GAAG;IACvB,aAAa,CAAC,KAAoB;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,WAAW,CAAC,KAAc;QACxB,OAAO,SAAS,CAAC,KAAK,CAAC;YACrB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;CACF,CAAC","sourcesContent":["import { isNullish, isString } from 'remeda';\nimport { Decimal } from 'decimal.js';\nimport {\n BuildInNumberAdapter,\n DecimalJsAdapter,\n NumberAdapter,\n} from './number-adapter/index.js';\nimport {\n BuildInIntlSegmenterAdapter,\n BuildInStringAdapter,\n GraphemeSplitterAdapter,\n StringAdapter,\n} from './string-adapter/index.js';\n\nexport class CounterAdapter {\n /**\n * 数字适配器, 有以下两种:\n * 1. BuildInNumberAdapter(默认): 使用内置 number 进行计算.\n * 2. DecimalJsAdapter: 使用 Decimal.js 进行计算.\n *\n * 详细信息请查看[字符长度限制](/guide/optional-dependencies#字符长度限制)章节.\n *\n * @default BuildInNumberAdapter\n */\n static NUMBER_ADAPTER: NumberAdapter = BuildInNumberAdapter();\n\n /**\n * 字符串适配器, 有以下两种:\n * 1. BuildInStringAdapter(默认): 使用内置 string 进行字符串处理.\n * 2. BuildInIntlSegmenterAdapter: 使用 Intl.Segmenter 进行字符串处理. 能够支持 emoji, 字符集.\n * 3. GraphemeSplitterAdapter: 使用 grapheme-splitter 进行字符串处理. 能够支持 emoji, 字符集.\n *\n * 详细信息请查看[支持 emoji 分词](/guide/optional-dependencies#支持-emoji-分词)章节.\n *\n * @default BuildInStringAdapter\n */\n static STRING_ADAPTER: StringAdapter = BuildInStringAdapter();\n\n /**\n * 将 value 及其相关的属性, 在 attribute 和 property 上的互相转换.\n *\n * @see https://lit.dev/docs/components/properties/#attributes\n * @protected\n */\n static VALUE_CONVERTER = {\n fromAttribute(value: string | null) {\n return value;\n },\n toAttribute(value: unknown) {\n return isNullish(value)\n ? value\n : CounterAdapter.NUMBER_ADAPTER.toString(value);\n },\n };\n\n static setNumberAdapter(\n adapterOrType: NumberAdapter | 'number' | 'decimal.js',\n config?: Decimal.Config,\n ) {\n let adapter: NumberAdapter = BuildInNumberAdapter();\n\n if (isString(adapterOrType)) {\n if (adapterOrType === 'number') adapter = BuildInNumberAdapter();\n else if (['decimal.js', 'decimaljs'].includes(adapterOrType))\n adapter = DecimalJsAdapter(config);\n } else {\n adapter = adapterOrType;\n }\n\n CounterAdapter.NUMBER_ADAPTER = adapter;\n }\n\n static setStringAdapter(\n adapterOrType:\n | StringAdapter\n | 'string'\n | 'intl-segmenter'\n | 'grapheme-splitter',\n ) {\n let adapter: StringAdapter = BuildInStringAdapter();\n\n if (isString(adapterOrType)) {\n if (adapterOrType === 'string') adapter = BuildInStringAdapter();\n else if (adapterOrType === 'intl-segmenter')\n adapter = BuildInIntlSegmenterAdapter();\n else if (adapterOrType === 'grapheme-splitter')\n adapter = GraphemeSplitterAdapter();\n } else {\n adapter = adapterOrType;\n }\n\n CounterAdapter.STRING_ADAPTER = adapter;\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export type TimeredCounterStyleSheets = Partial<{
2
+ 'timered-counter': string;
3
+ 'timered-counter-roller': string;
4
+ 'timered-counter-roller-digit': string;
5
+ }>;
6
+ export declare function getTimeredCounterStyleSheets(id: Symbol): TimeredCounterStyleSheets;
7
+ export declare function setTimeredCounterStyleSheets(id: Symbol, styles: string | TimeredCounterStyleSheets): void;
@@ -0,0 +1,15 @@
1
+ import { isString } from 'remeda';
2
+ import { parseJsonString } from './utils/parse-json-string.js';
3
+ const GlobalTimeredCounterStyleCache = new WeakMap();
4
+ export function getTimeredCounterStyleSheets(id) {
5
+ return GlobalTimeredCounterStyleCache.has(id)
6
+ ? GlobalTimeredCounterStyleCache.get(id)
7
+ : {};
8
+ }
9
+ export function setTimeredCounterStyleSheets(id, styles) {
10
+ const _styles = isString(styles)
11
+ ? parseJsonString(styles)
12
+ : styles;
13
+ GlobalTimeredCounterStyleCache.set(id, _styles);
14
+ }
15
+ //# sourceMappingURL=global-style-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-style-helper.js","sourceRoot":"","sources":["../../src/global-style-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAW/D,MAAM,8BAA8B,GAAG,IAAI,OAAO,EAG/C,CAAC;AAEJ,MAAM,UAAU,4BAA4B,CAC1C,EAAU;IAEV,OAAO,8BAA8B,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,CAAC,CAAC,8BAA8B,CAAC,GAAG,CAAC,EAAE,CAAE;QACzC,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,EAAU,EACV,MAA0C;IAE1C,MAAM,OAAO,GAA8B,QAAQ,CAAC,MAAM,CAAC;QACzD,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC;QACzB,CAAC,CAAC,MAAM,CAAC;IAEX,8BAA8B,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC","sourcesContent":["import { isString } from 'remeda';\nimport { parseJsonString } from './utils/parse-json-string.js';\n\nexport type TimeredCounterStyleSheets = Partial<{\n 'timered-counter': string;\n // 'timered-counter-datetime-duration': string;\n // 'timered-counter-number': string;\n // 'timered-counter-string': string;\n 'timered-counter-roller': string;\n 'timered-counter-roller-digit': string;\n}>;\n\nconst GlobalTimeredCounterStyleCache = new WeakMap<\n Symbol,\n TimeredCounterStyleSheets\n>();\n\nexport function getTimeredCounterStyleSheets(\n id: Symbol,\n): TimeredCounterStyleSheets {\n return GlobalTimeredCounterStyleCache.has(id)\n ? GlobalTimeredCounterStyleCache.get(id)!\n : {};\n}\n\nexport function setTimeredCounterStyleSheets(\n id: Symbol,\n styles: string | TimeredCounterStyleSheets,\n) {\n const _styles: TimeredCounterStyleSheets = isString(styles)\n ? parseJsonString(styles)\n : styles;\n\n GlobalTimeredCounterStyleCache.set(id, _styles);\n}\n"]}
@@ -31,7 +31,9 @@ export const CounterBaseMixin = (superClass) => {
31
31
  * 这对于初始化完成后启动动画效果非常有用.
32
32
  */
33
33
  get initialValue() {
34
- return this.numberAdapter.create(this.__initialValue);
34
+ return isNullish(this.__initialValue)
35
+ ? this.__initialValue
36
+ : this.numberAdapter.create(this.__initialValue);
35
37
  }
36
38
  set initialValue(value) {
37
39
  const old = this.__initialValue;
@@ -61,20 +63,13 @@ export const CounterBaseMixin = (superClass) => {
61
63
  // value: V = CounterBaseMixinClass.NUMBER_ADAPTER.create(0);
62
64
  this.__oldValue = CounterAdapter.NUMBER_ADAPTER.create(0);
63
65
  // oldValue: V = CounterBaseMixinClass.NUMBER_ADAPTER.create(0);
64
- this.__initialValue = CounterAdapter.NUMBER_ADAPTER.create(0);
66
+ this.__initialValue = null;
65
67
  this.__locale = 'en-US';
66
68
  this.localeInstance = isString(this.locale)
67
69
  ? new Intl.Locale(this.locale)
68
70
  : new Intl.Locale(...this.locale);
69
71
  this.direction = 'up';
70
72
  this.oldDirection = this.direction;
71
- /**
72
- * 第一次更新时, changedProperties 中 value 的旧值始终为 undefined.
73
- * 因此, 当 value 第一次更新时, oldValue 的值应当来自 initialValue 或 value.
74
- * 以保证 oldValue 始终有值.
75
- * @private
76
- */
77
- this.isValueFirstUpdate = true;
78
73
  // @ts-ignore
79
74
  this.numberAdapter = CounterAdapter.NUMBER_ADAPTER;
80
75
  // @ts-ignore
@@ -82,23 +77,28 @@ export const CounterBaseMixin = (superClass) => {
82
77
  }
83
78
  willUpdate(changedProperties) {
84
79
  super.willUpdate(changedProperties);
85
- if (changedProperties.has('value')) {
86
- if (this.isValueFirstUpdate) {
87
- this.isValueFirstUpdate = false;
88
- this.oldValue = isNonNullish(this.initialValue)
89
- ? this.initialValue
90
- : this.value;
91
- }
92
- else {
93
- this.oldValue = changedProperties.get('value') ?? this.oldValue;
94
- }
80
+ if (!changedProperties.has('oldValue')) {
81
+ // oldValue 未被手动设置时, 使用默认策略更新 oldValue.
82
+ this.oldValue = changedProperties.get('value') ?? this.value;
95
83
  }
96
84
  this.oldDirection = this.direction;
97
- this.direction = this.numberAdapter.gt(this.value, this.oldValue)
98
- ? 'down'
99
- : 'up';
85
+ if (!this.numberAdapter.eq(this.value, this.oldValue)) {
86
+ this.direction = this.numberAdapter.gt(this.value, this.oldValue)
87
+ ? 'down'
88
+ : 'up';
89
+ }
100
90
  // }
101
91
  }
92
+ /**
93
+ * oldValue 的默认初始值应当来自 initialValue 或 value.
94
+ * 以保证 oldValue 始终有值.
95
+ */
96
+ connectedCallback() {
97
+ super.connectedCallback();
98
+ this.oldValue = isNonNullish(this.initialValue)
99
+ ? this.initialValue
100
+ : this.value;
101
+ }
102
102
  }
103
103
  __decorate([
104
104
  property({
@@ -138,6 +138,7 @@ export const CounterBaseMixin = (superClass) => {
138
138
  return value;
139
139
  }
140
140
  },
141
+ reflect: true,
141
142
  noAccessor: true,
142
143
  })
143
144
  ], CounterBaseMixinClass.prototype, "locale", null);
@@ -1 +1 @@
1
- {"version":3,"file":"counter-base.js","sourceRoot":"","sources":["../../../src/mixins/counter-base.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, PropertyValues } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { isNonNullish, isNullish, isString } from 'remeda';\nimport { Constructor } from 'type-fest';\nimport {\n NumberAdapter,\n AvailableNumberAdapterValueType,\n} from '../number-adapter/index.js';\nimport { StringAdapter } from '../string-adapter/index.js';\nimport { CounterAdapter } from '../counter-adapter.js';\n\nexport declare class CounterBaseMixinInterface<\n V extends AvailableNumberAdapterValueType,\n> {\n static NUMBER_ADAPTER: NumberAdapter;\n\n static STRING_ADAPTER: StringAdapter;\n\n get value(): V;\n\n set value(value: V);\n\n get oldValue(): V;\n\n set oldValue(value: V);\n\n get initialValue(): V;\n\n set initialValue(value: V);\n\n direction: 'up' | 'down';\n\n oldDirection: 'up' | 'down';\n\n locale:\n | Intl.UnicodeBCP47LocaleIdentifier\n | [Intl.UnicodeBCP47LocaleIdentifier, Intl.LocaleOptions];\n\n localeInstance: Intl.Locale;\n\n numberAdapter: NumberAdapter;\n\n stringAdapter: StringAdapter;\n}\n\nexport const CounterBaseMixin = <\n V extends AvailableNumberAdapterValueType,\n T extends Constructor<LitElement> = Constructor<LitElement>,\n>(\n superClass: T,\n) => {\n class CounterBaseMixinClass extends superClass {\n private __value: V = CounterAdapter.NUMBER_ADAPTER.create(0);\n\n @property({\n attribute: 'value',\n reflect: true,\n converter: {\n toAttribute: CounterAdapter.VALUE_CONVERTER.toAttribute,\n },\n noAccessor: true,\n })\n get value() {\n return this.numberAdapter.create(this.__value);\n }\n\n set value(value: V) {\n value = CounterAdapter.NUMBER_ADAPTER.create(\n isNullish(value) || (isString(value) && value.trim() === '')\n ? 0\n : value,\n );\n\n const old = this.__value;\n this.__value = value;\n\n if (!this.numberAdapter.eq(this.__value, old)) {\n this.requestUpdate('value', old);\n }\n }\n // value: V = CounterBaseMixinClass.NUMBER_ADAPTER.create(0);\n\n private __oldValue: V = CounterAdapter.NUMBER_ADAPTER.create(0);\n\n @property({\n attribute: 'old-value',\n reflect: true,\n converter: CounterAdapter.VALUE_CONVERTER,\n noAccessor: true,\n })\n get oldValue() {\n return this.numberAdapter.create(this.__oldValue);\n }\n\n set oldValue(value: V) {\n const old = this.__oldValue;\n this.__oldValue = value;\n this.requestUpdate('oldValue', old);\n }\n // oldValue: V = CounterBaseMixinClass.NUMBER_ADAPTER.create(0);\n\n private __initialValue: V = CounterAdapter.NUMBER_ADAPTER.create(0);\n\n /**\n * 如果初始值被设置, 组件初始化时会使用该值而不是 `value`, 然后在初始化完成后, 将内部值更新为 `value`.\n *\n * 这对于初始化完成后启动动画效果非常有用.\n */\n @property({\n attribute: 'initial-value',\n reflect: true,\n converter: CounterAdapter.VALUE_CONVERTER,\n noAccessor: true,\n })\n get initialValue() {\n return this.numberAdapter.create(this.__initialValue);\n }\n\n set initialValue(value: V) {\n const old = this.__initialValue;\n this.__initialValue = value;\n this.requestUpdate('initialValue', old);\n }\n\n private __locale:\n | Intl.UnicodeBCP47LocaleIdentifier\n | [Intl.UnicodeBCP47LocaleIdentifier, Intl.LocaleOptions] = 'en-US';\n\n /**\n * 自定义本地化配置, 否则从浏览器环境中获取.\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale\n *\n * @default \"en-US\"\n */\n @property({\n converter: value => {\n if (isNullish(value)) return value;\n\n try {\n return JSON.parse(value);\n } catch (error) {\n return value;\n }\n },\n noAccessor: true,\n })\n get locale() {\n return this.__locale;\n }\n\n set locale(\n value:\n | Intl.UnicodeBCP47LocaleIdentifier\n | [Intl.UnicodeBCP47LocaleIdentifier, Intl.LocaleOptions],\n ) {\n const old = this.__locale;\n this.__locale = value;\n this.requestUpdate('locale', old);\n\n this.localeInstance = isString(this.__locale)\n ? new Intl.Locale(this.__locale)\n : new Intl.Locale(...this.__locale);\n }\n\n localeInstance: Intl.Locale = isString(this.locale)\n ? new Intl.Locale(this.locale)\n : new Intl.Locale(...this.locale);\n\n @state()\n direction: 'up' | 'down' = 'up';\n\n @state()\n oldDirection: 'up' | 'down' = this.direction;\n\n numberAdapter: NumberAdapter;\n\n stringAdapter: StringAdapter;\n\n constructor(...args: any[]) {\n super(...args);\n\n // @ts-ignore\n this.numberAdapter = CounterAdapter.NUMBER_ADAPTER;\n // @ts-ignore\n this.stringAdapter = CounterAdapter.STRING_ADAPTER;\n }\n\n /**\n * 第一次更新时, changedProperties 中 value 的旧值始终为 undefined.\n * 因此, 当 value 第一次更新时, oldValue 的值应当来自 initialValue 或 value.\n * 以保证 oldValue 始终有值.\n * @private\n */\n private isValueFirstUpdate = true;\n\n override willUpdate(changedProperties: PropertyValues<this>) {\n super.willUpdate(changedProperties);\n\n if (changedProperties.has('value')) {\n if (this.isValueFirstUpdate) {\n this.isValueFirstUpdate = false;\n this.oldValue = isNonNullish(this.initialValue)\n ? this.initialValue\n : this.value;\n } else {\n this.oldValue = changedProperties.get('value') ?? this.oldValue;\n }\n }\n\n this.oldDirection = this.direction;\n this.direction = this.numberAdapter.gt(this.value, this.oldValue)\n ? 'down'\n : 'up';\n // }\n }\n }\n\n return CounterBaseMixinClass as Constructor<CounterBaseMixinInterface<V>> & T;\n};\n"]}
1
+ {"version":3,"file":"counter-base.js","sourceRoot":"","sources":["../../../src/mixins/counter-base.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, PropertyValues } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { isNonNullish, isNullish, isString } from 'remeda';\nimport { Constructor } from 'type-fest';\nimport {\n NumberAdapter,\n AvailableNumberAdapterValueType,\n} from '../number-adapter/index.js';\nimport { StringAdapter } from '../string-adapter/index.js';\nimport { CounterAdapter } from '../counter-adapter.js';\n\nexport declare class CounterBaseMixinInterface<\n V extends AvailableNumberAdapterValueType,\n> {\n static NUMBER_ADAPTER: NumberAdapter;\n\n static STRING_ADAPTER: StringAdapter;\n\n get value(): V;\n\n set value(value: V);\n\n get oldValue(): V;\n\n set oldValue(value: V);\n\n get initialValue(): V;\n\n set initialValue(value: V);\n\n direction: 'up' | 'down';\n\n oldDirection: 'up' | 'down';\n\n locale:\n | Intl.UnicodeBCP47LocaleIdentifier\n | [Intl.UnicodeBCP47LocaleIdentifier, Intl.LocaleOptions];\n\n localeInstance: Intl.Locale;\n\n numberAdapter: NumberAdapter;\n\n stringAdapter: StringAdapter;\n}\n\nexport const CounterBaseMixin = <\n V extends AvailableNumberAdapterValueType,\n T extends Constructor<LitElement> = Constructor<LitElement>,\n>(\n superClass: T,\n) => {\n class CounterBaseMixinClass extends superClass {\n private __value: V = CounterAdapter.NUMBER_ADAPTER.create(0);\n\n @property({\n attribute: 'value',\n reflect: true,\n converter: {\n toAttribute: CounterAdapter.VALUE_CONVERTER.toAttribute,\n },\n noAccessor: true,\n })\n get value() {\n return this.numberAdapter.create(this.__value);\n }\n\n set value(value: V) {\n value = CounterAdapter.NUMBER_ADAPTER.create(\n isNullish(value) || (isString(value) && value.trim() === '')\n ? 0\n : value,\n );\n\n const old = this.__value;\n this.__value = value;\n\n if (!this.numberAdapter.eq(this.__value, old)) {\n this.requestUpdate('value', old);\n }\n }\n // value: V = CounterBaseMixinClass.NUMBER_ADAPTER.create(0);\n\n private __oldValue: V = CounterAdapter.NUMBER_ADAPTER.create(0);\n\n @property({\n attribute: 'old-value',\n reflect: true,\n converter: CounterAdapter.VALUE_CONVERTER,\n noAccessor: true,\n })\n get oldValue() {\n return this.numberAdapter.create(this.__oldValue);\n }\n\n set oldValue(value: V) {\n const old = this.__oldValue;\n this.__oldValue = value;\n this.requestUpdate('oldValue', old);\n }\n // oldValue: V = CounterBaseMixinClass.NUMBER_ADAPTER.create(0);\n\n private __initialValue: V | null = null;\n\n /**\n * 如果初始值被设置, 组件初始化时会使用该值而不是 `value`, 然后在初始化完成后, 将内部值更新为 `value`.\n *\n * 这对于初始化完成后启动动画效果非常有用.\n */\n @property({\n attribute: 'initial-value',\n reflect: true,\n converter: CounterAdapter.VALUE_CONVERTER,\n noAccessor: true,\n })\n get initialValue() {\n return isNullish(this.__initialValue)\n ? this.__initialValue\n : this.numberAdapter.create(this.__initialValue);\n }\n\n set initialValue(value: V | null) {\n const old = this.__initialValue;\n this.__initialValue = value;\n this.requestUpdate('initialValue', old);\n }\n\n private __locale:\n | Intl.UnicodeBCP47LocaleIdentifier\n | [Intl.UnicodeBCP47LocaleIdentifier, Intl.LocaleOptions] = 'en-US';\n\n /**\n * 自定义本地化配置, 否则从浏览器环境中获取.\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale\n *\n * @default \"en-US\"\n */\n @property({\n converter: value => {\n if (isNullish(value)) return value;\n\n try {\n return JSON.parse(value);\n } catch (error) {\n return value;\n }\n },\n reflect: true,\n noAccessor: true,\n })\n get locale() {\n return this.__locale;\n }\n\n set locale(\n value:\n | Intl.UnicodeBCP47LocaleIdentifier\n | [Intl.UnicodeBCP47LocaleIdentifier, Intl.LocaleOptions],\n ) {\n const old = this.__locale;\n this.__locale = value;\n this.requestUpdate('locale', old);\n\n this.localeInstance = isString(this.__locale)\n ? new Intl.Locale(this.__locale)\n : new Intl.Locale(...this.__locale);\n }\n\n localeInstance: Intl.Locale = isString(this.locale)\n ? new Intl.Locale(this.locale)\n : new Intl.Locale(...this.locale);\n\n @state()\n direction: 'up' | 'down' = 'up';\n\n @state()\n oldDirection: 'up' | 'down' = this.direction;\n\n numberAdapter: NumberAdapter;\n\n stringAdapter: StringAdapter;\n\n constructor(...args: any[]) {\n super(...args);\n\n // @ts-ignore\n this.numberAdapter = CounterAdapter.NUMBER_ADAPTER;\n // @ts-ignore\n this.stringAdapter = CounterAdapter.STRING_ADAPTER;\n }\n\n override willUpdate(changedProperties: PropertyValues<this>) {\n super.willUpdate(changedProperties);\n\n if (!changedProperties.has('oldValue')) {\n // oldValue 未被手动设置时, 使用默认策略更新 oldValue.\n this.oldValue = changedProperties.get('value') ?? this.value;\n }\n\n this.oldDirection = this.direction;\n if (!this.numberAdapter.eq(this.value, this.oldValue)) {\n this.direction = this.numberAdapter.gt(this.value, this.oldValue)\n ? 'down'\n : 'up';\n }\n // }\n }\n\n /**\n * oldValue 的默认初始值应当来自 initialValue 或 value.\n * 以保证 oldValue 始终有值.\n */\n override connectedCallback() {\n super.connectedCallback();\n\n this.oldValue = isNonNullish(this.initialValue)\n ? this.initialValue\n : this.value;\n }\n }\n\n return CounterBaseMixinClass as Constructor<CounterBaseMixinInterface<V>> & T;\n};\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=style-helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-helper.js","sourceRoot":"","sources":["../../src/style-helper.ts"],"names":[],"mappings":"","sourcesContent":[""]}
@@ -23,12 +23,17 @@ export declare class TimeredCounterDatetimeDuration extends TimeredCounter {
23
23
  * 通过 property 设置 value 时, 支持 Date 类型.
24
24
  */
25
25
  set value(value: any);
26
+ private __initialValuePlain;
27
+ get initialValue(): any;
28
+ /**
29
+ * 同 value
30
+ */
31
+ set initialValue(value: any);
26
32
  private __partsOptions;
27
33
  get partsOptions(): Partial<PartsOptions>;
28
34
  set partsOptions(value: Partial<PartsOptions>);
29
35
  private __from;
30
36
  private __to;
31
- private __durationInMilliseconds;
32
37
  private __minPrecision;
33
38
  private __maxPrecision;
34
39
  private __availableDurationParts;
@@ -36,7 +41,6 @@ export declare class TimeredCounterDatetimeDuration extends TimeredCounter {
36
41
  sampleSplit(samples: AvailableNumberAdapterValueType[]): AvailableNumberAdapterValueType[][];
37
42
  generateAriaLabel(): string;
38
43
  connectedCallback(): void;
39
- render(): import("lit-html").TemplateResult<1>;
40
44
  willUpdate(_changedProperties: PropertyValues): void;
41
- firstUpdated(_changedProperties: PropertyValues<this>): void;
45
+ render(): import("lit-html").TemplateResult<1>;
42
46
  }
@@ -3,7 +3,7 @@ import { customElement, property } from 'lit/decorators.js';
3
3
  import { html } from 'lit';
4
4
  import { repeat } from 'lit/directives/repeat.js';
5
5
  import { isArray, isDate, isNullish, isString, map } from 'remeda';
6
- import { isValid, toDate } from 'date-fns';
6
+ import { isValid, toDate, isBefore } from 'date-fns';
7
7
  import { TimeredCounter } from './timered-counter.js';
8
8
  import { DurationPartMillisecond, DurationPartType } from './types/duration.js';
9
9
  import { getLocalizedDateTimeFields } from './utils/localized-date-time-fields.js';
@@ -30,14 +30,33 @@ function optimizeFrom(from, to, minPrecision) {
30
30
  // 加上 deadlineDate 的余数, 消除精度误差.
31
31
  (toTS % minPrecisionMs));
32
32
  }
33
+ function toDurationInMilliseconds(value, minPrecision) {
34
+ if (isString(value))
35
+ value = parseJsonString(value);
36
+ if (!isArray(value))
37
+ value = [value, value];
38
+ const result = [
39
+ isDate(value[0]) ? value[0] : toDate(value[0]),
40
+ isDate(value[1]) ? value[1] : toDate(value[1]),
41
+ ];
42
+ if (!isValid(result[0]) || !isValid(result[1])) {
43
+ throw new Error(`value ${value[0]} or ${value[1]} is not a valid date.`);
44
+ }
45
+ const durationInMilliseconds = Math.abs(result[1].getTime() - optimizeFrom(result[0], result[1], minPrecision));
46
+ return {
47
+ durationInMilliseconds,
48
+ from: result[0],
49
+ to: result[1],
50
+ };
51
+ }
33
52
  let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extends TimeredCounter {
34
53
  constructor() {
35
54
  super(...arguments);
36
55
  this.__precision = [DurationPartType.Second, DurationPartType.Day];
56
+ this.__initialValuePlain = null;
37
57
  this.__partsOptions = null;
38
58
  this.__from = new Date();
39
59
  this.__to = new Date();
40
- this.__durationInMilliseconds = 0;
41
60
  this.__minPrecision = DurationPartType.Second;
42
61
  this.__maxPrecision = DurationPartType.Day;
43
62
  this.__availableDurationParts = [];
@@ -61,6 +80,28 @@ let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extend
61
80
  if (isString(value))
62
81
  value = parseJsonString(value);
63
82
  this.__precision = value;
83
+ /**
84
+ * `precision` 相关属性的更新需要立即更新, 以便于在 `value`, `initialValue` 等属性的 setter 中使用.
85
+ */
86
+ this.__minPrecision = isArray(this.__precision)
87
+ ? this.__precision[0]
88
+ : this.__precision;
89
+ this.__maxPrecision = isArray(this.__precision)
90
+ ? this.__precision[1]
91
+ : this.__precision;
92
+ this.__availableDurationParts = Object.values(DurationPartType)
93
+ .reverse()
94
+ .map(type => {
95
+ const minPrecisionBreakpoint = DurationPartMillisecond[this.__minPrecision];
96
+ const maxPrecisionBreakpoint = DurationPartMillisecond[this.__maxPrecision];
97
+ const partMilliseconds = DurationPartMillisecond[type];
98
+ return {
99
+ type,
100
+ available: partMilliseconds >= minPrecisionBreakpoint &&
101
+ partMilliseconds <= maxPrecisionBreakpoint,
102
+ };
103
+ })
104
+ .filter(part => part.available);
64
105
  }
65
106
  get value() {
66
107
  return super.value;
@@ -69,18 +110,21 @@ let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extend
69
110
  * 通过 property 设置 value 时, 支持 Date 类型.
70
111
  */
71
112
  set value(value) {
72
- if (isString(value))
73
- value = parseJsonString(value);
74
- if (!isArray(value))
75
- value = [value, value];
76
- this.__from = isDate(value[0]) ? value[0] : toDate(value[0]);
77
- this.__to = isDate(value[1]) ? value[1] : toDate(value[1]);
78
- if (!isValid(this.__from) || !isValid(this.__to)) {
79
- throw new Error(`value ${value[0]} or ${value[1]} is not a valid date.`);
80
- }
81
- this.__durationInMilliseconds = Math.abs(this.__to.getTime() -
82
- optimizeFrom(this.__from, this.__to, this.__minPrecision));
83
- super.value = this.__durationInMilliseconds;
113
+ const { from, to, durationInMilliseconds } = toDurationInMilliseconds(value, this.__minPrecision);
114
+ this.__from = from;
115
+ this.__to = to;
116
+ super.value = durationInMilliseconds;
117
+ }
118
+ get initialValue() {
119
+ return super.initialValue;
120
+ }
121
+ /**
122
+ * value
123
+ */
124
+ set initialValue(value) {
125
+ this.__initialValuePlain = value;
126
+ const { durationInMilliseconds } = toDurationInMilliseconds(value, this.__minPrecision);
127
+ super.initialValue = durationInMilliseconds;
84
128
  }
85
129
  get partsOptions() {
86
130
  return super.partsOptions;
@@ -106,11 +150,26 @@ let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extend
106
150
  return tempParts;
107
151
  }
108
152
  generateAriaLabel() {
109
- return iso8601Duration(durationObject(new Date(Math.min(this.__durationInMilliseconds, 0)), new Date(Math.max(this.__durationInMilliseconds, 0)), map(this.__availableDurationParts, part => part.type)));
153
+ return iso8601Duration(durationObject(isBefore(this.__from, this.__to) ? this.__from : this.__to, isBefore(this.__from, this.__to) ? this.__to : this.__from, map(this.__availableDurationParts, part => part.type)));
110
154
  }
111
155
  connectedCallback() {
112
- super.connectedCallback();
113
156
  this.role = 'timer';
157
+ /**
158
+ * TimeredCounterDatetimeDuration 将 `minPlaces` 默认设置为 `[2]`. 实例化时需要手动触发 `partsOptions` 的 setter.
159
+ */
160
+ this.partsOptions = this.__partsOptions ?? {};
161
+ this.initialValue = this.__initialValuePlain;
162
+ /**
163
+ * 类似上方的 partsOptions, precision 也需要在初始化时手动触发 setter. 以此确保 __minPrecision, __maxPrecision, __availableDurationParts 有值.
164
+ */
165
+ this.precision = this.__precision;
166
+ super.connectedCallback();
167
+ }
168
+ willUpdate(_changedProperties) {
169
+ super.willUpdate(_changedProperties);
170
+ if (_changedProperties.has('locale')) {
171
+ this.__dateTimeFieldLabels = getLocalizedDateTimeFields(this.localeInstance);
172
+ }
114
173
  }
115
174
  render() {
116
175
  const cellStyles = this.extractCellStyles();
@@ -136,55 +195,13 @@ let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extend
136
195
  .direction=${this.direction}
137
196
  @roller-animation-start=${this.dispatchTimeredCounterAnimationStart}
138
197
  @roller-animation-end=${this.dispatchTimeredCounterAnimationEnd}
139
- >
140
- <slot name="prefix" slot="prefix"></slot>
141
- <slot name="suffix" slot="suffix"></slot>
142
- ${repeat(this.parts, (_, index) => index, (_, partIndex) => html `<span slot=${`part-suffix-${partIndex}`} class="duration-unit"
198
+ ><slot name="prefix" slot="prefix"></slot
199
+ ><slot name="suffix" slot="suffix"></slot>${repeat(this.parts, (_, index) => index, (_, partIndex) => html `<span slot=${`part-suffix-${partIndex}`} class="duration-unit"
143
200
  >${this.__dateTimeFieldLabels[availableDurationPartTypes[partIndex]]}</span
144
201
  >`)}
145
202
  </timered-counter-roller>
146
203
  `;
147
204
  }
148
- willUpdate(_changedProperties) {
149
- /**
150
- * precision 相关属性的更新需要在 super.willUpdate 之前进行, 以便在 super.willUpdate 中使用到.
151
- *
152
- * __availableDurationParts 在 sampleSplit 中使用到, 而 sampleSplit 又会在 super.willUpdate 中使用(准确来说是 `CounterPartsMixinClass`).
153
- * 所以需要在 super.willUpdate 之前更新.
154
- */
155
- if (_changedProperties.has('precision')) {
156
- this.__minPrecision = isArray(this.precision)
157
- ? this.precision[0]
158
- : this.precision;
159
- this.__maxPrecision = isArray(this.precision)
160
- ? this.precision[1]
161
- : this.precision;
162
- this.__availableDurationParts = Object.values(DurationPartType)
163
- .reverse()
164
- .map(type => {
165
- const minPrecisionBreakpoint = DurationPartMillisecond[this.__minPrecision];
166
- const maxPrecisionBreakpoint = DurationPartMillisecond[this.__maxPrecision];
167
- const partMilliseconds = DurationPartMillisecond[type];
168
- return {
169
- type,
170
- available: partMilliseconds >= minPrecisionBreakpoint &&
171
- partMilliseconds <= maxPrecisionBreakpoint,
172
- };
173
- })
174
- .filter(part => part.available);
175
- }
176
- super.willUpdate(_changedProperties);
177
- if (_changedProperties.has('locale')) {
178
- this.__dateTimeFieldLabels = getLocalizedDateTimeFields(this.localeInstance);
179
- }
180
- }
181
- firstUpdated(_changedProperties) {
182
- super.firstUpdated(_changedProperties);
183
- /**
184
- * TimeredCounterDatetimeDuration 将 `minPlaces` 默认设置为 `[2]`. 实例化时需要手动触发 `partsOptions` 的 setter.
185
- */
186
- this.partsOptions = this.__partsOptions ?? {};
187
- }
188
205
  };
189
206
  TimeredCounterDatetimeDuration.styles = [...TimeredCounter.styles, timeredCounterDatetimeStyles];
190
207
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"timered-counter-datetime-duration.js","sourceRoot":"","sources":["../../src/timered-counter-datetime-duration.ts"],"names":[],"mappings":"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","sourcesContent":["import { customElement, property } from 'lit/decorators.js';\nimport { html, PropertyValues } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { isArray, isDate, isNullish, isString, map } from 'remeda';\nimport { isValid, toDate } from 'date-fns';\nimport { TimeredCounter } from './timered-counter.js';\nimport { AvailableNumberAdapterValueType } from './number-adapter/index.js';\nimport { DurationPartMillisecond, DurationPartType } from './types/duration.js';\nimport { getLocalizedDateTimeFields } from './utils/localized-date-time-fields.js';\nimport { duration, durationObject } from './utils/duration.js';\nimport { iso8601Duration } from './utils/iso8601-duration.js';\nimport { timeredCounterDatetimeStyles } from './styles/timered-counter-datetime-styles.js';\nimport { parseJsonString } from './utils/parse-json-string.js';\nimport { PartsOptions } from './mixins/counter-parts.js';\n\n/**\n * 根据最小精度对 from 进行优化. 避免频繁更新.\n *\n * 1. from 先会被减小到 minPrecisionMs 的整数倍.\n * 2. 如果 from 和 to 的差值不是 minPrecisionMs 的整数倍, 则再加上/减去一个 minPrecisionMs 的值. 加上或减去取决于 from 和 to 的谁更大.\n * 这相当于将 from 中小于 minPrecisionMs 的值舍入到 minPrecisionMs 的整数倍.\n * 3. 加上 to 余 minPrecisionMs 的值, 保证 from 与 to 的差值是 minPrecisionMs 的整数倍.\n */\nfunction optimizeFrom(from: Date, to: Date, minPrecision: DurationPartType) {\n const minPrecisionMs = DurationPartMillisecond[minPrecision];\n const fromTS = from.getTime();\n const toTS = to.getTime();\n\n const base = fromTS - (fromTS % minPrecisionMs);\n const offset = Math.abs(toTS - fromTS) % minPrecisionMs;\n\n return (\n base +\n (offset > 0 ? (fromTS < toTS ? -1 : 1) * minPrecisionMs : 0) +\n // 加上 deadlineDate 的余数, 消除精度误差.\n (toTS % minPrecisionMs)\n );\n}\n\n@customElement('timered-counter-datetime-duration')\nexport class TimeredCounterDatetimeDuration extends TimeredCounter {\n static styles = [...TimeredCounter.styles, timeredCounterDatetimeStyles];\n\n private __precision: DurationPartType | [DurationPartType, DurationPartType] =\n [DurationPartType.Second, DurationPartType.Day];\n\n /**\n * 计数器显示的精度.\n * 1. 当为单个值时, 表示最小精度.\n * 2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.\n *\n * @default [DurationPartType.Second, DurationPartType.Day]\n *\n * @example DurationPartType.Second 显示从年份到秒数的所有精度.\n * @example [DurationPartType.Second, DurationPartType.Day] 显示从天数到秒数的所有精度.\n * @example [DurationPartType.Millisecond, DurationPartType.Year] 显示从年份到毫秒的所有精度.\n */\n @property({\n reflect: true,\n converter: value => {\n if (isNullish(value)) return value;\n\n return parseJsonString(value);\n },\n })\n get precision() {\n return this.__precision;\n }\n\n set precision(value: any) {\n if (isString(value)) value = parseJsonString(value);\n\n this.__precision = value;\n }\n\n get value() {\n return super.value;\n }\n\n /**\n * 通过 property 设置 value 时, 支持 Date 类型.\n */\n set value(value: any) {\n if (isString(value)) value = parseJsonString(value);\n\n if (!isArray(value)) value = [value, value];\n\n this.__from = isDate(value[0]) ? value[0] : toDate(value[0]);\n this.__to = isDate(value[1]) ? value[1] : toDate(value[1]);\n if (!isValid(this.__from) || !isValid(this.__to)) {\n throw new Error(`value ${value[0]} or ${value[1]} is not a valid date.`);\n }\n\n this.__durationInMilliseconds = Math.abs(\n this.__to.getTime() -\n optimizeFrom(this.__from, this.__to, this.__minPrecision),\n );\n\n super.value = this.__durationInMilliseconds;\n }\n\n private __partsOptions: Partial<PartsOptions> | null = null;\n\n get partsOptions(): Partial<PartsOptions> {\n return super.partsOptions;\n }\n\n set partsOptions(value: Partial<PartsOptions>) {\n this.__partsOptions = value;\n super.partsOptions = {\n minPlaces: [2, undefined],\n ...this.__partsOptions,\n };\n }\n\n private __from: Date = new Date();\n\n private __to: Date = new Date();\n\n private __durationInMilliseconds = 0;\n\n private __minPrecision: DurationPartType = DurationPartType.Second;\n\n private __maxPrecision: DurationPartType = DurationPartType.Day;\n\n private __availableDurationParts = [] as {\n type: DurationPartType;\n available: boolean;\n }[];\n\n private __dateTimeFieldLabels = {} as Record<DurationPartType, string>;\n\n override sampleSplit(\n samples: AvailableNumberAdapterValueType[],\n ): AvailableNumberAdapterValueType[][] {\n const availableDurationPartTypes = map(\n this.__availableDurationParts,\n part => part.type,\n );\n\n const tempParts = availableDurationPartTypes.map(() => [] as number[]);\n for (const n of samples) {\n const num = this.numberAdapter.toNumber(n);\n /**\n * 计算并保存每个在 {@link precision} 范围内的时间部分的值\n */\n const availablePartValues = duration(\n new Date(Math.min(num, 0)),\n new Date(Math.max(num, 0)),\n availableDurationPartTypes,\n );\n availablePartValues.forEach((value, i) => tempParts[i].push(value));\n }\n\n return tempParts;\n }\n\n override generateAriaLabel(): string {\n return iso8601Duration(\n durationObject(\n new Date(Math.min(this.__durationInMilliseconds, 0)),\n new Date(Math.max(this.__durationInMilliseconds, 0)),\n map(this.__availableDurationParts, part => part.type),\n ),\n );\n }\n\n override connectedCallback() {\n super.connectedCallback();\n\n this.role = 'timer';\n }\n\n override render() {\n const cellStyles = this.extractCellStyles();\n const digitStyles = this.extractDigitStyles();\n const partStyles = this.extractPartStyles();\n\n const animationOptions = this.extractAnimationOptions();\n const keyframes = this.extractKeyframes();\n\n const availableDurationPartTypes = map(\n this.__availableDurationParts,\n part => part.type,\n );\n\n return html`\n <timered-counter-roller\n class=\"timered-counter timered-counter-datetime-duration\"\n exportparts=\"prefix, suffix, part-suffix\"\n aria-hidden=\"true\"\n color=${this.color}\n .parentContainerRect=${this.partsContainerRect}\n .parts=${this.parts}\n .partPreprocessDataList=${this.partPreprocessDataList}\n .animationOptions=${animationOptions}\n .keyframes=${keyframes}\n .cellStyles=${cellStyles}\n .digitStyles=${digitStyles}\n .partStyles=${partStyles}\n .direction=${this.direction}\n @roller-animation-start=${this.dispatchTimeredCounterAnimationStart}\n @roller-animation-end=${this.dispatchTimeredCounterAnimationEnd}\n >\n <slot name=\"prefix\" slot=\"prefix\"></slot>\n <slot name=\"suffix\" slot=\"suffix\"></slot>\n ${repeat(\n this.parts,\n (_, index) => index,\n (_, partIndex) =>\n html`<span slot=${`part-suffix-${partIndex}`} class=\"duration-unit\"\n >${this.__dateTimeFieldLabels[\n availableDurationPartTypes[partIndex]\n ]}</span\n >`,\n )}\n </timered-counter-roller>\n `;\n }\n\n override willUpdate(_changedProperties: PropertyValues) {\n /**\n * precision 相关属性的更新需要在 super.willUpdate 之前进行, 以便在 super.willUpdate 中使用到.\n *\n * __availableDurationParts 在 sampleSplit 中使用到, 而 sampleSplit 又会在 super.willUpdate 中使用(准确来说是 `CounterPartsMixinClass`).\n * 所以需要在 super.willUpdate 之前更新.\n */\n if (_changedProperties.has('precision')) {\n this.__minPrecision = isArray(this.precision)\n ? this.precision[0]\n : this.precision;\n this.__maxPrecision = isArray(this.precision)\n ? this.precision[1]\n : this.precision;\n\n this.__availableDurationParts = Object.values(DurationPartType)\n .reverse()\n .map(type => {\n const minPrecisionBreakpoint =\n DurationPartMillisecond[this.__minPrecision];\n const maxPrecisionBreakpoint =\n DurationPartMillisecond[this.__maxPrecision];\n const partMilliseconds = DurationPartMillisecond[type];\n return {\n type,\n available:\n partMilliseconds >= minPrecisionBreakpoint &&\n partMilliseconds <= maxPrecisionBreakpoint,\n };\n })\n .filter(part => part.available);\n }\n\n super.willUpdate(_changedProperties);\n\n if (_changedProperties.has('locale')) {\n this.__dateTimeFieldLabels = getLocalizedDateTimeFields(\n this.localeInstance,\n );\n }\n }\n\n override firstUpdated(_changedProperties: PropertyValues<this>) {\n super.firstUpdated(_changedProperties);\n\n /**\n * TimeredCounterDatetimeDuration 将 `minPlaces` 默认设置为 `[2]`. 实例化时需要手动触发 `partsOptions` 的 setter.\n */\n this.partsOptions = this.__partsOptions ?? {};\n }\n}\n"]}
1
+ {"version":3,"file":"timered-counter-datetime-duration.js","sourceRoot":"","sources":["../../src/timered-counter-datetime-duration.ts"],"names":[],"mappings":"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","sourcesContent":["import { customElement, property } from 'lit/decorators.js';\nimport { html, PropertyValues } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { isArray, isDate, isNullish, isString, map } from 'remeda';\nimport { isValid, toDate, isBefore } from 'date-fns';\nimport { TimeredCounter } from './timered-counter.js';\nimport { AvailableNumberAdapterValueType } from './number-adapter/index.js';\nimport { DurationPartMillisecond, DurationPartType } from './types/duration.js';\nimport { getLocalizedDateTimeFields } from './utils/localized-date-time-fields.js';\nimport { duration, durationObject } from './utils/duration.js';\nimport { iso8601Duration } from './utils/iso8601-duration.js';\nimport { timeredCounterDatetimeStyles } from './styles/timered-counter-datetime-styles.js';\nimport { parseJsonString } from './utils/parse-json-string.js';\nimport { PartsOptions } from './mixins/counter-parts.js';\n\n/**\n * 根据最小精度对 from 进行优化. 避免频繁更新.\n *\n * 1. from 先会被减小到 minPrecisionMs 的整数倍.\n * 2. 如果 from 和 to 的差值不是 minPrecisionMs 的整数倍, 则再加上/减去一个 minPrecisionMs 的值. 加上或减去取决于 from 和 to 的谁更大.\n * 这相当于将 from 中小于 minPrecisionMs 的值舍入到 minPrecisionMs 的整数倍.\n * 3. 加上 to 余 minPrecisionMs 的值, 保证 from 与 to 的差值是 minPrecisionMs 的整数倍.\n */\nfunction optimizeFrom(from: Date, to: Date, minPrecision: DurationPartType) {\n const minPrecisionMs = DurationPartMillisecond[minPrecision];\n const fromTS = from.getTime();\n const toTS = to.getTime();\n\n const base = fromTS - (fromTS % minPrecisionMs);\n const offset = Math.abs(toTS - fromTS) % minPrecisionMs;\n\n return (\n base +\n (offset > 0 ? (fromTS < toTS ? -1 : 1) * minPrecisionMs : 0) +\n // 加上 deadlineDate 的余数, 消除精度误差.\n (toTS % minPrecisionMs)\n );\n}\n\nfunction toDurationInMilliseconds(value: any, minPrecision: DurationPartType) {\n if (isString(value)) value = parseJsonString(value);\n\n if (!isArray(value)) value = [value, value];\n\n const result = [\n isDate(value[0]) ? value[0] : toDate(value[0]),\n isDate(value[1]) ? value[1] : toDate(value[1]),\n ] as const;\n\n if (!isValid(result[0]) || !isValid(result[1])) {\n throw new Error(`value ${value[0]} or ${value[1]} is not a valid date.`);\n }\n\n const durationInMilliseconds = Math.abs(\n result[1].getTime() - optimizeFrom(result[0], result[1], minPrecision),\n );\n\n return {\n durationInMilliseconds,\n from: result[0],\n to: result[1],\n };\n}\n\n@customElement('timered-counter-datetime-duration')\nexport class TimeredCounterDatetimeDuration extends TimeredCounter {\n static styles = [...TimeredCounter.styles, timeredCounterDatetimeStyles];\n\n private __precision: DurationPartType | [DurationPartType, DurationPartType] =\n [DurationPartType.Second, DurationPartType.Day];\n\n /**\n * 计数器显示的精度.\n * 1. 当为单个值时, 表示最小精度.\n * 2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.\n *\n * @default [DurationPartType.Second, DurationPartType.Day]\n *\n * @example DurationPartType.Second 显示从年份到秒数的所有精度.\n * @example [DurationPartType.Second, DurationPartType.Day] 显示从天数到秒数的所有精度.\n * @example [DurationPartType.Millisecond, DurationPartType.Year] 显示从年份到毫秒的所有精度.\n */\n @property({\n reflect: true,\n converter: value => {\n if (isNullish(value)) return value;\n\n return parseJsonString(value);\n },\n })\n get precision() {\n return this.__precision;\n }\n\n set precision(value: any) {\n if (isString(value)) value = parseJsonString(value);\n\n this.__precision = value;\n\n /**\n * `precision` 相关属性的更新需要立即更新, 以便于在 `value`, `initialValue` 等属性的 setter 中使用.\n */\n this.__minPrecision = isArray(this.__precision)\n ? this.__precision[0]\n : this.__precision;\n this.__maxPrecision = isArray(this.__precision)\n ? this.__precision[1]\n : this.__precision;\n\n this.__availableDurationParts = Object.values(DurationPartType)\n .reverse()\n .map(type => {\n const minPrecisionBreakpoint =\n DurationPartMillisecond[this.__minPrecision];\n const maxPrecisionBreakpoint =\n DurationPartMillisecond[this.__maxPrecision];\n const partMilliseconds = DurationPartMillisecond[type];\n return {\n type,\n available:\n partMilliseconds >= minPrecisionBreakpoint &&\n partMilliseconds <= maxPrecisionBreakpoint,\n };\n })\n .filter(part => part.available);\n }\n\n get value() {\n return super.value;\n }\n\n /**\n * 通过 property 设置 value 时, 支持 Date 类型.\n */\n set value(value: any) {\n const { from, to, durationInMilliseconds } = toDurationInMilliseconds(\n value,\n this.__minPrecision,\n );\n\n this.__from = from;\n this.__to = to;\n super.value = durationInMilliseconds;\n }\n\n private __initialValuePlain: any = null;\n\n get initialValue() {\n return super.initialValue;\n }\n\n /**\n * 同 value\n */\n set initialValue(value: any) {\n this.__initialValuePlain = value;\n\n const { durationInMilliseconds } = toDurationInMilliseconds(\n value,\n this.__minPrecision,\n );\n super.initialValue = durationInMilliseconds;\n }\n\n private __partsOptions: Partial<PartsOptions> | null = null;\n\n get partsOptions(): Partial<PartsOptions> {\n return super.partsOptions;\n }\n\n set partsOptions(value: Partial<PartsOptions>) {\n this.__partsOptions = value;\n super.partsOptions = {\n minPlaces: [2, undefined],\n ...this.__partsOptions,\n };\n }\n\n private __from: Date = new Date();\n\n private __to: Date = new Date();\n\n private __minPrecision: DurationPartType = DurationPartType.Second;\n\n private __maxPrecision: DurationPartType = DurationPartType.Day;\n\n private __availableDurationParts = [] as {\n type: DurationPartType;\n available: boolean;\n }[];\n\n private __dateTimeFieldLabels = {} as Record<DurationPartType, string>;\n\n override sampleSplit(\n samples: AvailableNumberAdapterValueType[],\n ): AvailableNumberAdapterValueType[][] {\n const availableDurationPartTypes = map(\n this.__availableDurationParts,\n part => part.type,\n );\n\n const tempParts = availableDurationPartTypes.map(() => [] as number[]);\n for (const n of samples) {\n const num = this.numberAdapter.toNumber(n);\n /**\n * 计算并保存每个在 {@link precision} 范围内的时间部分的值\n */\n const availablePartValues = duration(\n new Date(Math.min(num, 0)),\n new Date(Math.max(num, 0)),\n availableDurationPartTypes,\n );\n availablePartValues.forEach((value, i) => tempParts[i].push(value));\n }\n\n return tempParts;\n }\n\n override generateAriaLabel(): string {\n return iso8601Duration(\n durationObject(\n isBefore(this.__from, this.__to) ? this.__from : this.__to,\n isBefore(this.__from, this.__to) ? this.__to : this.__from,\n map(this.__availableDurationParts, part => part.type),\n ),\n );\n }\n\n override connectedCallback() {\n this.role = 'timer';\n\n /**\n * TimeredCounterDatetimeDuration 将 `minPlaces` 默认设置为 `[2]`. 实例化时需要手动触发 `partsOptions` 的 setter.\n */\n this.partsOptions = this.__partsOptions ?? {};\n\n this.initialValue = this.__initialValuePlain;\n\n /**\n * 类似上方的 partsOptions, precision 也需要在初始化时手动触发 setter. 以此确保 __minPrecision, __maxPrecision, __availableDurationParts 有值.\n */\n this.precision = this.__precision;\n\n super.connectedCallback();\n }\n\n override willUpdate(_changedProperties: PropertyValues) {\n super.willUpdate(_changedProperties);\n\n if (_changedProperties.has('locale')) {\n this.__dateTimeFieldLabels = getLocalizedDateTimeFields(\n this.localeInstance,\n );\n }\n }\n\n override render() {\n const cellStyles = this.extractCellStyles();\n const digitStyles = this.extractDigitStyles();\n const partStyles = this.extractPartStyles();\n\n const animationOptions = this.extractAnimationOptions();\n const keyframes = this.extractKeyframes();\n\n const availableDurationPartTypes = map(\n this.__availableDurationParts,\n part => part.type,\n );\n\n return html`\n <timered-counter-roller\n class=\"timered-counter timered-counter-datetime-duration\"\n exportparts=\"prefix, suffix, part-suffix\"\n aria-hidden=\"true\"\n color=${this.color}\n .parentContainerRect=${this.partsContainerRect}\n .parts=${this.parts}\n .partPreprocessDataList=${this.partPreprocessDataList}\n .animationOptions=${animationOptions}\n .keyframes=${keyframes}\n .cellStyles=${cellStyles}\n .digitStyles=${digitStyles}\n .partStyles=${partStyles}\n .direction=${this.direction}\n @roller-animation-start=${this.dispatchTimeredCounterAnimationStart}\n @roller-animation-end=${this.dispatchTimeredCounterAnimationEnd}\n ><slot name=\"prefix\" slot=\"prefix\"></slot\n ><slot name=\"suffix\" slot=\"suffix\"></slot>${repeat(\n this.parts,\n (_, index) => index,\n (_, partIndex) =>\n html`<span slot=${`part-suffix-${partIndex}`} class=\"duration-unit\"\n >${this.__dateTimeFieldLabels[\n availableDurationPartTypes[partIndex]\n ]}</span\n >`,\n )}\n </timered-counter-roller>\n `;\n }\n}\n"]}
@@ -17,6 +17,11 @@ export declare class TimeredCounterNumber extends TimeredCounter {
17
17
  * @see https://en.wikipedia.org/wiki/Decimal_separator
18
18
  */
19
19
  localDecimalSeparator: string;
20
+ /**
21
+ * 本地化数字格式化配置中的分组分隔符.
22
+ * @see https://en.wikipedia.org/wiki/Decimal_separator#Digit_grouping
23
+ */
24
+ localeGroupingSeparator: string;
20
25
  sampleToString(value: AvailableNumberAdapterValueType): string;
21
26
  render(): import("lit-html").TemplateResult<1>;
22
27
  willUpdate(_changedProperties: PropertyValues<this>): void;
@@ -21,7 +21,12 @@ let TimeredCounterNumber = class TimeredCounterNumber extends TimeredCounter {
21
21
  * 本地化数字格式化配置中的小数点分隔符. 根据不同的地区可能是 `.` 或 `,`.
22
22
  * @see https://en.wikipedia.org/wiki/Decimal_separator
23
23
  */
24
- this.localDecimalSeparator = '.';
24
+ this.localDecimalSeparator = '';
25
+ /**
26
+ * 本地化数字格式化配置中的分组分隔符.
27
+ * @see https://en.wikipedia.org/wiki/Decimal_separator#Digit_grouping
28
+ */
29
+ this.localeGroupingSeparator = '';
25
30
  }
26
31
  sampleToString(value) {
27
32
  return this.localeNumber
@@ -70,10 +75,11 @@ let TimeredCounterNumber = class TimeredCounterNumber extends TimeredCounter {
70
75
  * 本地化数字格式化配置变化时, 更新 `partsOptions` 中的 `decimalSeparator`.
71
76
  */
72
77
  {
73
- const decimalSeparator = this.localeNumberInstance
74
- .formatToParts(123456.789)
75
- .find(part => part.type === 'decimal')?.value || '.';
76
- if (this.localDecimalSeparator !== decimalSeparator) {
78
+ const numberParts = this.localeNumberInstance.formatToParts(123456.789);
79
+ const decimalSeparator = numberParts.find(part => part.type === 'decimal')?.value || '.';
80
+ const groupingSeparator = numberParts.find(part => part.type === 'group')?.value || '';
81
+ if (this.localDecimalSeparator !== decimalSeparator ||
82
+ this.localeGroupingSeparator !== groupingSeparator) {
77
83
  this.localDecimalSeparator = decimalSeparator;
78
84
  const oldPartsOptions = this.partsOptions;
79
85
  this.partsOptions = {
@@ -92,12 +98,12 @@ __decorate([
92
98
  property({
93
99
  converter: value => {
94
100
  if (isNullish(value))
95
- return value;
101
+ return false;
96
102
  try {
97
103
  return JSON.parse(value);
98
104
  }
99
105
  catch (error) {
100
- return value;
106
+ return true;
101
107
  }
102
108
  },
103
109
  reflect: true,
@@ -107,6 +113,9 @@ __decorate([
107
113
  __decorate([
108
114
  state()
109
115
  ], TimeredCounterNumber.prototype, "localDecimalSeparator", void 0);
116
+ __decorate([
117
+ state()
118
+ ], TimeredCounterNumber.prototype, "localeGroupingSeparator", void 0);
110
119
  TimeredCounterNumber = __decorate([
111
120
  customElement('timered-counter-number')
112
121
  ], TimeredCounterNumber);