timered-counter 1.1.0 → 1.2.0

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.
@@ -318,7 +318,7 @@
318
318
  {
319
319
  "kind": "field",
320
320
  "name": "precision",
321
- "description": "计数器显示的精度.\n1. 当为单个值时, 表示最小精度.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
321
+ "description": "计数器显示的精度.\n1. 当为单个值时, 仅显示该精度的时间部分.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
322
322
  "default": "[DurationPartType.Second, DurationPartType.Day]",
323
323
  "attribute": "precision",
324
324
  "reflects": true
@@ -457,6 +457,29 @@
457
457
  "module": "src/mixins/counter-aira.ts"
458
458
  }
459
459
  },
460
+ {
461
+ "kind": "method",
462
+ "name": "shouldRebuildParts",
463
+ "return": {
464
+ "type": {
465
+ "text": "boolean"
466
+ }
467
+ },
468
+ "parameters": [
469
+ {
470
+ "name": "changedProperties",
471
+ "type": {
472
+ "text": "PropertyValues<this>"
473
+ }
474
+ }
475
+ ],
476
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
477
+ "privacy": "protected",
478
+ "inheritedFrom": {
479
+ "name": "CounterPartsMixin",
480
+ "module": "src/mixins/counter-parts.ts"
481
+ }
482
+ },
460
483
  {
461
484
  "kind": "field",
462
485
  "name": "ariaLabel",
@@ -1029,7 +1052,7 @@
1029
1052
  "attributes": [
1030
1053
  {
1031
1054
  "name": "precision",
1032
- "description": "计数器显示的精度.\n1. 当为单个值时, 表示最小精度.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
1055
+ "description": "计数器显示的精度.\n1. 当为单个值时, 仅显示该精度的时间部分.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
1033
1056
  "default": "[DurationPartType.Second, DurationPartType.Day]",
1034
1057
  "fieldName": "precision"
1035
1058
  },
@@ -1706,6 +1729,29 @@
1706
1729
  "module": "src/mixins/counter-parts.ts"
1707
1730
  }
1708
1731
  },
1732
+ {
1733
+ "kind": "method",
1734
+ "name": "shouldRebuildParts",
1735
+ "return": {
1736
+ "type": {
1737
+ "text": "boolean"
1738
+ }
1739
+ },
1740
+ "parameters": [
1741
+ {
1742
+ "name": "changedProperties",
1743
+ "type": {
1744
+ "text": "PropertyValues<this>"
1745
+ }
1746
+ }
1747
+ ],
1748
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
1749
+ "privacy": "protected",
1750
+ "inheritedFrom": {
1751
+ "name": "CounterPartsMixin",
1752
+ "module": "src/mixins/counter-parts.ts"
1753
+ }
1754
+ },
1709
1755
  {
1710
1756
  "kind": "method",
1711
1757
  "name": "processPartData",
@@ -2660,6 +2706,29 @@
2660
2706
  "module": "src/mixins/counter-parts.ts"
2661
2707
  }
2662
2708
  },
2709
+ {
2710
+ "kind": "method",
2711
+ "name": "shouldRebuildParts",
2712
+ "return": {
2713
+ "type": {
2714
+ "text": "boolean"
2715
+ }
2716
+ },
2717
+ "parameters": [
2718
+ {
2719
+ "name": "changedProperties",
2720
+ "type": {
2721
+ "text": "PropertyValues<this>"
2722
+ }
2723
+ }
2724
+ ],
2725
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
2726
+ "privacy": "protected",
2727
+ "inheritedFrom": {
2728
+ "name": "CounterPartsMixin",
2729
+ "module": "src/mixins/counter-parts.ts"
2730
+ }
2731
+ },
2663
2732
  {
2664
2733
  "kind": "method",
2665
2734
  "name": "processPartData",
@@ -3512,6 +3581,29 @@
3512
3581
  "module": "src/mixins/counter-parts.ts"
3513
3582
  }
3514
3583
  },
3584
+ {
3585
+ "kind": "method",
3586
+ "name": "shouldRebuildParts",
3587
+ "return": {
3588
+ "type": {
3589
+ "text": "boolean"
3590
+ }
3591
+ },
3592
+ "parameters": [
3593
+ {
3594
+ "name": "changedProperties",
3595
+ "type": {
3596
+ "text": "PropertyValues<this>"
3597
+ }
3598
+ }
3599
+ ],
3600
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
3601
+ "privacy": "protected",
3602
+ "inheritedFrom": {
3603
+ "name": "CounterPartsMixin",
3604
+ "module": "src/mixins/counter-parts.ts"
3605
+ }
3606
+ },
3515
3607
  {
3516
3608
  "kind": "method",
3517
3609
  "name": "processPartData",
@@ -5093,6 +5185,23 @@
5093
5185
  }
5094
5186
  }
5095
5187
  ]
5188
+ },
5189
+ {
5190
+ "kind": "method",
5191
+ "name": "shouldRebuildParts",
5192
+ "return": {
5193
+ "type": {
5194
+ "text": "boolean"
5195
+ }
5196
+ },
5197
+ "parameters": [
5198
+ {
5199
+ "name": "changedProperties",
5200
+ "type": {
5201
+ "text": "PropertyValues<this>"
5202
+ }
5203
+ }
5204
+ ]
5096
5205
  }
5097
5206
  ]
5098
5207
  },
@@ -5195,6 +5304,25 @@
5195
5304
  }
5196
5305
  ]
5197
5306
  },
5307
+ {
5308
+ "kind": "method",
5309
+ "name": "shouldRebuildParts",
5310
+ "return": {
5311
+ "type": {
5312
+ "text": "boolean"
5313
+ }
5314
+ },
5315
+ "parameters": [
5316
+ {
5317
+ "name": "changedProperties",
5318
+ "type": {
5319
+ "text": "PropertyValues<this>"
5320
+ }
5321
+ }
5322
+ ],
5323
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
5324
+ "privacy": "protected"
5325
+ },
5198
5326
  {
5199
5327
  "kind": "method",
5200
5328
  "name": "processPartData",
@@ -7204,7 +7332,7 @@
7204
7332
  "type": {
7205
7333
  "text": "StoryObj<TimeredCounterDatetimeDuration>"
7206
7334
  },
7207
- "default": "{ args: { className: 'test-target', animationOptions: { duration: 100, }, }, async play(context) { const { canvasElement, step } = context; const counter = canvasElement.querySelector( '.test-target', ) as TimeredCounterDatetimeDuration; const list = [ ...range(0, 2).map(v => [new Date(), addSeconds(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addMinutes(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addHours(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addDays(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addMonths(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addYears(new Date(), v)]), ]; await step('Testing with attribute', async () => { await valueChange(context, { counter, list, setBy: setByAttr, equal }); }); await step('Testing with property', async () => { await valueChange(context, { counter, list, setBy: setByProp, equal }); }); }, }"
7335
+ "default": "{ args: { className: 'test-target', animationOptions: { duration: 100, }, precision: [DurationPartType.Millisecond, DurationPartType.Day], }, async play(context) { const { canvasElement, step } = context; const counter = canvasElement.querySelector( '.test-target', ) as TimeredCounterDatetimeDuration; const date = new Date('2025-06-10T09:43:36Z'); const list = [ ...range(0, 2).map(v => [date, addMilliseconds(date, v)]), ...range(0, 2).map(v => [date, addSeconds(date, v)]), ...range(0, 2).map(v => [date, addMinutes(date, v)]), ...range(0, 2).map(v => [date, addHours(date, v)]), ...range(0, 2).map(v => [date, addDays(date, v)]), ...range(0, 2).map(v => [date, addMonths(date, v)]), ...range(0, 2).map(v => [date, addYears(date, v)]), ]; await step('Testing with attribute', async () => { await valueChange(context, { counter, list, setBy: setByAttr, equal }); }); await step('Testing with property', async () => { await valueChange(context, { counter, list, setBy: setByProp, equal }); }); }, }"
7208
7336
  },
7209
7337
  {
7210
7338
  "kind": "variable",
@@ -8049,7 +8177,7 @@
8049
8177
  "type": {
8050
8178
  "text": "ResizeObserver"
8051
8179
  },
8052
- "default": "new ResizeObserver(() => { this.digitWidth = ( this.clonedRollDigitList ? this.clonedRollDigitList.getBoundingClientRect() : new DOMRect() ).width; })"
8180
+ "default": "new ResizeObserver(() => { this.digitWidth = this.clonedRollDigitList ? this.clonedRollDigitList.offsetWidth : 0; })"
8053
8181
  },
8054
8182
  {
8055
8183
  "kind": "field",
@@ -8473,7 +8601,7 @@
8473
8601
  {
8474
8602
  "kind": "variable",
8475
8603
  "name": "rollerStyles",
8476
- "default": "css` :host { display: inline-flex; overflow: hidden; /** inline-block 和 overflow-hidden 同时存在会使得基线为下边缘. 手动设置 align-bottom 以修正这个问题. @see https://stackoverflow.com/questions/22421782/css-overflow-hidden-increases-height-of-container @see https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align */ vertical-align: bottom; } .counter-parts { display: inline-flex; flex: 1 1 auto; } .roller-part { display: inline-flex; white-space: nowrap; } .roller__prefix, .roller__suffix { flex: none; } .roller-part .roller-part__wrapper { display: inline-block; } .roller-part .roller-part__suffix { display: inline-block; } `"
8604
+ "default": "css` :host { display: inline-flex; overflow: hidden; /** inline-block 和 overflow-hidden 同时存在会使得基线为下边缘. 手动设置 align-bottom 以修正这个问题. @see https://stackoverflow.com/questions/22421782/css-overflow-hidden-increases-height-of-container @see https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align */ vertical-align: bottom; } .counter-parts { display: inline-flex; flex: 1 1 auto; } .roller-part { display: inline-flex; white-space: nowrap; } .roller__prefix, .roller__suffix { flex: none; } .roller-part .roller-part__wrapper { display: inline-block; text-align: center; } .roller-part .roller-part__suffix { display: inline-block; } `"
8477
8605
  },
8478
8606
  {
8479
8607
  "kind": "variable",
@@ -318,7 +318,7 @@
318
318
  {
319
319
  "kind": "field",
320
320
  "name": "precision",
321
- "description": "计数器显示的精度.\n1. 当为单个值时, 表示最小精度.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
321
+ "description": "计数器显示的精度.\n1. 当为单个值时, 仅显示该精度的时间部分.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
322
322
  "default": "[DurationPartType.Second, DurationPartType.Day]",
323
323
  "attribute": "precision",
324
324
  "reflects": true
@@ -457,6 +457,29 @@
457
457
  "module": "src/mixins/counter-aira.ts"
458
458
  }
459
459
  },
460
+ {
461
+ "kind": "method",
462
+ "name": "shouldRebuildParts",
463
+ "return": {
464
+ "type": {
465
+ "text": "boolean"
466
+ }
467
+ },
468
+ "parameters": [
469
+ {
470
+ "name": "changedProperties",
471
+ "type": {
472
+ "text": "PropertyValues<this>"
473
+ }
474
+ }
475
+ ],
476
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
477
+ "privacy": "protected",
478
+ "inheritedFrom": {
479
+ "name": "CounterPartsMixin",
480
+ "module": "src/mixins/counter-parts.ts"
481
+ }
482
+ },
460
483
  {
461
484
  "kind": "field",
462
485
  "name": "ariaLabel",
@@ -1029,7 +1052,7 @@
1029
1052
  "attributes": [
1030
1053
  {
1031
1054
  "name": "precision",
1032
- "description": "计数器显示的精度.\n1. 当为单个值时, 表示最小精度.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
1055
+ "description": "计数器显示的精度.\n1. 当为单个值时, 仅显示该精度的时间部分.\n2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.",
1033
1056
  "default": "[DurationPartType.Second, DurationPartType.Day]",
1034
1057
  "fieldName": "precision"
1035
1058
  },
@@ -1706,6 +1729,29 @@
1706
1729
  "module": "src/mixins/counter-parts.ts"
1707
1730
  }
1708
1731
  },
1732
+ {
1733
+ "kind": "method",
1734
+ "name": "shouldRebuildParts",
1735
+ "return": {
1736
+ "type": {
1737
+ "text": "boolean"
1738
+ }
1739
+ },
1740
+ "parameters": [
1741
+ {
1742
+ "name": "changedProperties",
1743
+ "type": {
1744
+ "text": "PropertyValues<this>"
1745
+ }
1746
+ }
1747
+ ],
1748
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
1749
+ "privacy": "protected",
1750
+ "inheritedFrom": {
1751
+ "name": "CounterPartsMixin",
1752
+ "module": "src/mixins/counter-parts.ts"
1753
+ }
1754
+ },
1709
1755
  {
1710
1756
  "kind": "method",
1711
1757
  "name": "processPartData",
@@ -2660,6 +2706,29 @@
2660
2706
  "module": "src/mixins/counter-parts.ts"
2661
2707
  }
2662
2708
  },
2709
+ {
2710
+ "kind": "method",
2711
+ "name": "shouldRebuildParts",
2712
+ "return": {
2713
+ "type": {
2714
+ "text": "boolean"
2715
+ }
2716
+ },
2717
+ "parameters": [
2718
+ {
2719
+ "name": "changedProperties",
2720
+ "type": {
2721
+ "text": "PropertyValues<this>"
2722
+ }
2723
+ }
2724
+ ],
2725
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
2726
+ "privacy": "protected",
2727
+ "inheritedFrom": {
2728
+ "name": "CounterPartsMixin",
2729
+ "module": "src/mixins/counter-parts.ts"
2730
+ }
2731
+ },
2663
2732
  {
2664
2733
  "kind": "method",
2665
2734
  "name": "processPartData",
@@ -3512,6 +3581,29 @@
3512
3581
  "module": "src/mixins/counter-parts.ts"
3513
3582
  }
3514
3583
  },
3584
+ {
3585
+ "kind": "method",
3586
+ "name": "shouldRebuildParts",
3587
+ "return": {
3588
+ "type": {
3589
+ "text": "boolean"
3590
+ }
3591
+ },
3592
+ "parameters": [
3593
+ {
3594
+ "name": "changedProperties",
3595
+ "type": {
3596
+ "text": "PropertyValues<this>"
3597
+ }
3598
+ }
3599
+ ],
3600
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
3601
+ "privacy": "protected",
3602
+ "inheritedFrom": {
3603
+ "name": "CounterPartsMixin",
3604
+ "module": "src/mixins/counter-parts.ts"
3605
+ }
3606
+ },
3515
3607
  {
3516
3608
  "kind": "method",
3517
3609
  "name": "processPartData",
@@ -5093,6 +5185,23 @@
5093
5185
  }
5094
5186
  }
5095
5187
  ]
5188
+ },
5189
+ {
5190
+ "kind": "method",
5191
+ "name": "shouldRebuildParts",
5192
+ "return": {
5193
+ "type": {
5194
+ "text": "boolean"
5195
+ }
5196
+ },
5197
+ "parameters": [
5198
+ {
5199
+ "name": "changedProperties",
5200
+ "type": {
5201
+ "text": "PropertyValues<this>"
5202
+ }
5203
+ }
5204
+ ]
5096
5205
  }
5097
5206
  ]
5098
5207
  },
@@ -5195,6 +5304,25 @@
5195
5304
  }
5196
5305
  ]
5197
5306
  },
5307
+ {
5308
+ "kind": "method",
5309
+ "name": "shouldRebuildParts",
5310
+ "return": {
5311
+ "type": {
5312
+ "text": "boolean"
5313
+ }
5314
+ },
5315
+ "parameters": [
5316
+ {
5317
+ "name": "changedProperties",
5318
+ "type": {
5319
+ "text": "PropertyValues<this>"
5320
+ }
5321
+ }
5322
+ ],
5323
+ "description": "判断是否需要重新生成 parts 数据.\n\nprocessPartData 依赖 partsOptions 和 value 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.",
5324
+ "privacy": "protected"
5325
+ },
5198
5326
  {
5199
5327
  "kind": "method",
5200
5328
  "name": "processPartData",
@@ -7204,7 +7332,7 @@
7204
7332
  "type": {
7205
7333
  "text": "StoryObj<TimeredCounterDatetimeDuration>"
7206
7334
  },
7207
- "default": "{ args: { className: 'test-target', animationOptions: { duration: 100, }, }, async play(context) { const { canvasElement, step } = context; const counter = canvasElement.querySelector( '.test-target', ) as TimeredCounterDatetimeDuration; const list = [ ...range(0, 2).map(v => [new Date(), addSeconds(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addMinutes(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addHours(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addDays(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addMonths(new Date(), v)]), ...range(0, 2).map(v => [new Date(), addYears(new Date(), v)]), ]; await step('Testing with attribute', async () => { await valueChange(context, { counter, list, setBy: setByAttr, equal }); }); await step('Testing with property', async () => { await valueChange(context, { counter, list, setBy: setByProp, equal }); }); }, }"
7335
+ "default": "{ args: { className: 'test-target', animationOptions: { duration: 100, }, precision: [DurationPartType.Millisecond, DurationPartType.Day], }, async play(context) { const { canvasElement, step } = context; const counter = canvasElement.querySelector( '.test-target', ) as TimeredCounterDatetimeDuration; const date = new Date('2025-06-10T09:43:36Z'); const list = [ ...range(0, 2).map(v => [date, addMilliseconds(date, v)]), ...range(0, 2).map(v => [date, addSeconds(date, v)]), ...range(0, 2).map(v => [date, addMinutes(date, v)]), ...range(0, 2).map(v => [date, addHours(date, v)]), ...range(0, 2).map(v => [date, addDays(date, v)]), ...range(0, 2).map(v => [date, addMonths(date, v)]), ...range(0, 2).map(v => [date, addYears(date, v)]), ]; await step('Testing with attribute', async () => { await valueChange(context, { counter, list, setBy: setByAttr, equal }); }); await step('Testing with property', async () => { await valueChange(context, { counter, list, setBy: setByProp, equal }); }); }, }"
7208
7336
  },
7209
7337
  {
7210
7338
  "kind": "variable",
@@ -8049,7 +8177,7 @@
8049
8177
  "type": {
8050
8178
  "text": "ResizeObserver"
8051
8179
  },
8052
- "default": "new ResizeObserver(() => { this.digitWidth = ( this.clonedRollDigitList ? this.clonedRollDigitList.getBoundingClientRect() : new DOMRect() ).width; })"
8180
+ "default": "new ResizeObserver(() => { this.digitWidth = this.clonedRollDigitList ? this.clonedRollDigitList.offsetWidth : 0; })"
8053
8181
  },
8054
8182
  {
8055
8183
  "kind": "field",
@@ -8473,7 +8601,7 @@
8473
8601
  {
8474
8602
  "kind": "variable",
8475
8603
  "name": "rollerStyles",
8476
- "default": "css` :host { display: inline-flex; overflow: hidden; /** inline-block 和 overflow-hidden 同时存在会使得基线为下边缘. 手动设置 align-bottom 以修正这个问题. @see https://stackoverflow.com/questions/22421782/css-overflow-hidden-increases-height-of-container @see https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align */ vertical-align: bottom; } .counter-parts { display: inline-flex; flex: 1 1 auto; } .roller-part { display: inline-flex; white-space: nowrap; } .roller__prefix, .roller__suffix { flex: none; } .roller-part .roller-part__wrapper { display: inline-block; } .roller-part .roller-part__suffix { display: inline-block; } `"
8604
+ "default": "css` :host { display: inline-flex; overflow: hidden; /** inline-block 和 overflow-hidden 同时存在会使得基线为下边缘. 手动设置 align-bottom 以修正这个问题. @see https://stackoverflow.com/questions/22421782/css-overflow-hidden-increases-height-of-container @see https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align */ vertical-align: bottom; } .counter-parts { display: inline-flex; flex: 1 1 auto; } .roller-part { display: inline-flex; white-space: nowrap; } .roller__prefix, .roller__suffix { flex: none; } .roller-part .roller-part__wrapper { display: inline-block; text-align: center; } .roller-part .roller-part__suffix { display: inline-block; } `"
8477
8605
  },
8478
8606
  {
8479
8607
  "kind": "variable",
@@ -1,3 +1,4 @@
1
+ import { PropertyValues } from 'lit';
1
2
  import { Constructor } from 'type-fest';
2
3
  import { CounterBaseMixin } from './counter-base.js';
3
4
  import { PartData } from '../types/group.js';
@@ -38,5 +39,6 @@ export declare class CounterPartsMixinInterface<V extends AvailableNumberAdapter
38
39
  sampling(from: V, to: V): V[];
39
40
  sampleSplit(samples: V[]): V[][];
40
41
  sampleToString(value: V): string;
42
+ shouldRebuildParts(changedProperties: PropertyValues<this>): boolean;
41
43
  }
42
44
  export declare const CounterPartsMixin: <V extends AvailableNumberAdapterValueType, T extends ReturnType<typeof CounterBaseMixin<V>> = Constructor<import("./counter-base.js").CounterBaseMixinInterface<V>> & Constructor<import("lit").LitElement>>(superClass: T) => Constructor<CounterPartsMixinInterface<V>> & T;
@@ -64,17 +64,24 @@ export const CounterPartsMixin = (superClass) => {
64
64
  sampleToString(value) {
65
65
  return this.numberAdapter.toString(value);
66
66
  }
67
+ /**
68
+ * 判断是否需要重新生成 parts 数据.
69
+ *
70
+ * {@link processPartData} 依赖 {@link partsOptions} 和 {@link value} 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.
71
+ *
72
+ * @param changedProperties
73
+ * @protected
74
+ */
75
+ // eslint-disable-next-line class-methods-use-this
76
+ shouldRebuildParts(changedProperties) {
77
+ return (changedProperties.has('value') || changedProperties.has('partsOptions'));
78
+ }
67
79
  willUpdate(changedProperties) {
68
80
  super.willUpdate(changedProperties);
69
81
  if (changedProperties.has('value')) {
70
82
  this.oldParts = this.parts;
71
83
  }
72
- /**
73
- * {@link processPartData} 依赖 {@link partsOptions} 和 {@link value} 生成数据.
74
- * 当依赖项没有变化时, 不需要重新生成数据.
75
- */
76
- if (changedProperties.has('value') ||
77
- changedProperties.has('partsOptions')) {
84
+ if (this.shouldRebuildParts(changedProperties)) {
78
85
  this.parts = this.processPartData();
79
86
  }
80
87
  if (changedProperties.has('value')) {
@@ -1 +1 @@
1
- {"version":3,"file":"counter-parts.js","sourceRoot":"","sources":["../../../src/mixins/counter-parts.ts"],"names":[],"mappings":"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","sourcesContent":["import { PropertyValues } from 'lit';\nimport { zip } from 'd3-array';\nimport { Constructor } from 'type-fest';\nimport { property } from 'lit/decorators.js';\nimport { isArray, isObjectType } from 'remeda';\nimport { CounterBaseMixin } from './counter-base.js';\nimport { PartData } from '../types/group.js';\nimport { transitionDigit } from '../utils/transition-digit.js';\nimport {\n PartPreprocessedData,\n preprocessPartData,\n} from '../utils/preprocess-part-data.js';\nimport { AvailableNumberAdapterValueType } from '../number-adapter/index.js';\nimport { parseJsonString } from '../utils/parse-json-string.js';\n\nexport interface PartsOptions {\n sampleCount: number;\n /**\n * 可以通过该属性将数字转换为你想要的任意字符串.\n */\n digitToChar: Record<string | number, string> | string[];\n /**\n * 小数点分隔符.\n */\n decimalSeparator: string;\n /**\n * 当**位数不足**时, 强制补全的 [整数, 小数] 位数. 为空时位数自适应.\n */\n minPlaces: [number | undefined, number | undefined];\n fillChar: string;\n /**\n * 数据类型.\n *\n * 1. `'string'`: 字符串类型.\n * 1. 不会使用 `decimalSeparator` 截取小数部分.\n * 2. `'number'`: 数字类型.\n *\n * @default `'number'`\n */\n type: 'string' | 'number';\n}\ntype InnerPartsOptions = Omit<PartsOptions, 'digitToChar'> & {\n digitToChar: Record<string | number, string>;\n};\n\nexport declare class CounterPartsMixinInterface<\n V extends AvailableNumberAdapterValueType,\n> {\n parts: PartData[];\n\n oldParts: PartData[];\n\n partPreprocessDataList: PartPreprocessedData[][];\n\n get partsOptions(): Partial<PartsOptions>;\n\n set partsOptions(value: Partial<PartsOptions>);\n\n sampling(from: V, to: V): V[];\n\n sampleSplit(samples: V[]): V[][];\n\n sampleToString(value: V): string;\n}\n\nfunction toChar(value: number) {\n return String.fromCodePoint(value + 48);\n}\n\nfunction preprocessPartsOptions(options: PartsOptions): InnerPartsOptions {\n const digitToChar: Record<string, string> = {};\n\n if (isArray(options.digitToChar)) {\n options.digitToChar.forEach((char, index) => {\n digitToChar[toChar(index)] = char;\n });\n } else if (isObjectType(options.digitToChar)) {\n Object.entries(options.digitToChar).forEach(([key, value]) => {\n digitToChar[key] = value;\n });\n }\n\n return {\n ...options,\n digitToChar,\n };\n}\n\nexport const CounterPartsMixin = <\n V extends AvailableNumberAdapterValueType,\n T extends ReturnType<typeof CounterBaseMixin<V>> = ReturnType<\n typeof CounterBaseMixin<V>\n >,\n>(\n superClass: T,\n) => {\n class CounterPartsMixinClass extends superClass {\n private static DEFAULT_PARTS_OPTIONS: InnerPartsOptions = {\n sampleCount: 16,\n decimalSeparator: '.',\n fillChar: '0',\n minPlaces: [1, 0],\n digitToChar: {},\n type: 'number',\n };\n\n #__partsOptions: InnerPartsOptions = {\n ...CounterPartsMixinClass.DEFAULT_PARTS_OPTIONS,\n };\n\n /**\n * 这是 `usePartData` 的配置项. `usePartData` 被用于从数值的变化中生成用于滚动的数据.\n * 这里不会有太多解释, 因为它是一个底层的配置项. 你可以查看 `CounterPartsMixinClass` 的源码了解更多信息.\n */\n @property({\n type: Object,\n attribute: 'parts-options',\n converter: value => parseJsonString(value ?? '') ?? {},\n noAccessor: true,\n })\n get partsOptions(): InnerPartsOptions {\n return this.#__partsOptions;\n }\n\n set partsOptions(value: Partial<PartsOptions>) {\n const old = this.#__partsOptions;\n this.#__partsOptions = preprocessPartsOptions({\n ...CounterPartsMixinClass.DEFAULT_PARTS_OPTIONS,\n ...value,\n });\n this.requestUpdate('partsOptions', old);\n }\n // partsOptions: InnerPartsOptions =\n // CounterPartsMixinClass.DEFAULT_PARTS_OPTIONS;\n\n parts: PartData[] = [];\n\n oldParts: PartData[] = [];\n\n partPreprocessDataList: PartPreprocessedData[][] = [];\n\n sampling(from: V, to: V) {\n return transitionDigit(\n this.numberAdapter,\n this.numberAdapter.max(from, to),\n this.numberAdapter.min(from, to),\n this.partsOptions.sampleCount,\n );\n }\n\n // eslint-disable-next-line class-methods-use-this\n sampleSplit(samples: V[]) {\n return [samples.slice()];\n }\n\n sampleToString(value: V) {\n return this.numberAdapter.toString(value);\n }\n\n override willUpdate(changedProperties: PropertyValues<this>) {\n super.willUpdate(changedProperties);\n\n if (changedProperties.has('value')) {\n this.oldParts = this.parts;\n }\n\n /**\n * {@link processPartData} 依赖 {@link partsOptions} 和 {@link value} 生成数据.\n * 当依赖项没有变化时, 不需要重新生成数据.\n */\n if (\n changedProperties.has('value') ||\n changedProperties.has('partsOptions')\n ) {\n this.parts = this.processPartData();\n }\n\n if (changedProperties.has('value')) {\n this.partPreprocessDataList = preprocessPartData(\n this.direction,\n this.parts,\n this.oldDirection,\n this.oldParts,\n );\n }\n\n /**\n * `value` 没变但 `direction` 变化时, 也要重新生成 `partPreprocessDataList`.\n */\n // todo test events 和 animationOptions 冲突\n // if (\n // changedProperties.has('value') ||\n // changedProperties.has('direction')\n // ) {\n // }\n }\n\n /**\n * process:\n * 1. 采样\n * 2. 转换\n * 3. 构造\n */\n private processPartData() {\n const { decimalSeparator, digitToChar, minPlaces, fillChar, type } =\n this.partsOptions;\n\n const from = this.value;\n const to = this.oldValue;\n\n let _sampleToString: (value: V) => string[] = value =>\n this.sampleToString(value).split(decimalSeparator);\n if (type === 'string') {\n _sampleToString = value => [this.sampleToString(value), ''];\n }\n\n const result: PartData[] = [];\n\n /**\n * 对 {@link from} 到 {@link to} 的范围采样.\n */\n const tempParts = this.sampleSplit(this.sampling(from, to));\n\n /**\n * 将时间部分的数字转换为用于滚动的字符串数组\n *\n * headNumber: 最先显示的数字. 向下滚动时, 为滚动列表的最后一个数字, 向上滚动时相反.\n * tailNumber: 最后显示的数字. 向下滚动时, 为滚动列表的第一个数字, 向上滚动时相反.\n */\n {\n const directionValue = this.numberAdapter.gt(from, to) ? 'down' : 'up';\n for (let i = 0; i < tempParts.length; i++) {\n const partData = tempParts[i];\n // const headNumber =\n // partData[directionValue === \"down\" ? partData.length - 1 : 0];\n const tailNumber =\n partData[directionValue === 'down' ? 0 : partData.length - 1];\n\n const [minIntegerPlaces = 1, minDecimalPlaces = 0] = minPlaces;\n\n const numberParts = _sampleToString(tailNumber);\n const integerPlaces = Math.max(\n // numberParts[0].length,\n this.stringAdapter.stringToChars(numberParts[0]).length,\n minIntegerPlaces,\n );\n const decimalPlaces = Math.max(\n // numberParts[1]?.length ?? 0,\n this.stringAdapter.stringToChars(numberParts[1] ?? '').length,\n minDecimalPlaces,\n );\n\n /**\n * 使用 zip 将二维矩阵, 旋转90度\n */\n const data = zip(\n ...partData\n /**\n * 保证位数一致, 向前补零\n */\n .map(digitData => {\n const [integer = '', decimal = ''] = _sampleToString(digitData);\n\n const integerChars = this.stringAdapter.stringToChars(integer);\n const decimalChars = this.stringAdapter.stringToChars(decimal);\n\n const filledIntegerPlaces = Math.max(\n integerPlaces - integerChars.length,\n 0,\n );\n\n const filledDecimalPlaces = Math.max(\n decimalPlaces - decimalChars.length,\n 0,\n );\n\n let filledChars = ([] as string[]).concat(\n new Array(filledIntegerPlaces).fill(fillChar),\n integerChars,\n );\n if (decimalPlaces > 0) {\n filledChars = filledChars.concat(\n [decimalSeparator],\n decimalChars,\n new Array(filledDecimalPlaces).fill(fillChar),\n );\n }\n return filledChars;\n }),\n )\n /**\n * 删除连续的重复项\n */\n .map((digitList, index, array) => ({\n data: digitList\n .filter(\n (digit, digitIndex, digitArray) =>\n digitIndex === 0 || digit !== digitArray[digitIndex - 1],\n )\n .map(digit => digitToChar[digit] ?? digit),\n place: array.length - index,\n }));\n\n result.push({\n digits: data,\n });\n }\n }\n\n return result;\n }\n }\n\n return CounterPartsMixinClass as Constructor<CounterPartsMixinInterface<V>> &\n T;\n};\n"]}
1
+ {"version":3,"file":"counter-parts.js","sourceRoot":"","sources":["../../../src/mixins/counter-parts.ts"],"names":[],"mappings":"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","sourcesContent":["import { PropertyValues } from 'lit';\nimport { zip } from 'd3-array';\nimport { Constructor } from 'type-fest';\nimport { property } from 'lit/decorators.js';\nimport { isArray, isObjectType } from 'remeda';\nimport { CounterBaseMixin } from './counter-base.js';\nimport { PartData } from '../types/group.js';\nimport { transitionDigit } from '../utils/transition-digit.js';\nimport {\n PartPreprocessedData,\n preprocessPartData,\n} from '../utils/preprocess-part-data.js';\nimport { AvailableNumberAdapterValueType } from '../number-adapter/index.js';\nimport { parseJsonString } from '../utils/parse-json-string.js';\n\nexport interface PartsOptions {\n sampleCount: number;\n /**\n * 可以通过该属性将数字转换为你想要的任意字符串.\n */\n digitToChar: Record<string | number, string> | string[];\n /**\n * 小数点分隔符.\n */\n decimalSeparator: string;\n /**\n * 当**位数不足**时, 强制补全的 [整数, 小数] 位数. 为空时位数自适应.\n */\n minPlaces: [number | undefined, number | undefined];\n fillChar: string;\n /**\n * 数据类型.\n *\n * 1. `'string'`: 字符串类型.\n * 1. 不会使用 `decimalSeparator` 截取小数部分.\n * 2. `'number'`: 数字类型.\n *\n * @default `'number'`\n */\n type: 'string' | 'number';\n}\ntype InnerPartsOptions = Omit<PartsOptions, 'digitToChar'> & {\n digitToChar: Record<string | number, string>;\n};\n\nexport declare class CounterPartsMixinInterface<\n V extends AvailableNumberAdapterValueType,\n> {\n parts: PartData[];\n\n oldParts: PartData[];\n\n partPreprocessDataList: PartPreprocessedData[][];\n\n get partsOptions(): Partial<PartsOptions>;\n\n set partsOptions(value: Partial<PartsOptions>);\n\n sampling(from: V, to: V): V[];\n\n sampleSplit(samples: V[]): V[][];\n\n sampleToString(value: V): string;\n\n shouldRebuildParts(changedProperties: PropertyValues<this>): boolean;\n}\n\nfunction toChar(value: number) {\n return String.fromCodePoint(value + 48);\n}\n\nfunction preprocessPartsOptions(options: PartsOptions): InnerPartsOptions {\n const digitToChar: Record<string, string> = {};\n\n if (isArray(options.digitToChar)) {\n options.digitToChar.forEach((char, index) => {\n digitToChar[toChar(index)] = char;\n });\n } else if (isObjectType(options.digitToChar)) {\n Object.entries(options.digitToChar).forEach(([key, value]) => {\n digitToChar[key] = value;\n });\n }\n\n return {\n ...options,\n digitToChar,\n };\n}\n\nexport const CounterPartsMixin = <\n V extends AvailableNumberAdapterValueType,\n T extends ReturnType<typeof CounterBaseMixin<V>> = ReturnType<\n typeof CounterBaseMixin<V>\n >,\n>(\n superClass: T,\n) => {\n class CounterPartsMixinClass extends superClass {\n private static DEFAULT_PARTS_OPTIONS: InnerPartsOptions = {\n sampleCount: 16,\n decimalSeparator: '.',\n fillChar: '0',\n minPlaces: [1, 0],\n digitToChar: {},\n type: 'number',\n };\n\n #__partsOptions: InnerPartsOptions = {\n ...CounterPartsMixinClass.DEFAULT_PARTS_OPTIONS,\n };\n\n /**\n * 这是 `usePartData` 的配置项. `usePartData` 被用于从数值的变化中生成用于滚动的数据.\n * 这里不会有太多解释, 因为它是一个底层的配置项. 你可以查看 `CounterPartsMixinClass` 的源码了解更多信息.\n */\n @property({\n type: Object,\n attribute: 'parts-options',\n converter: value => parseJsonString(value ?? '') ?? {},\n noAccessor: true,\n })\n get partsOptions(): InnerPartsOptions {\n return this.#__partsOptions;\n }\n\n set partsOptions(value: Partial<PartsOptions>) {\n const old = this.#__partsOptions;\n this.#__partsOptions = preprocessPartsOptions({\n ...CounterPartsMixinClass.DEFAULT_PARTS_OPTIONS,\n ...value,\n });\n this.requestUpdate('partsOptions', old);\n }\n // partsOptions: InnerPartsOptions =\n // CounterPartsMixinClass.DEFAULT_PARTS_OPTIONS;\n\n parts: PartData[] = [];\n\n oldParts: PartData[] = [];\n\n partPreprocessDataList: PartPreprocessedData[][] = [];\n\n sampling(from: V, to: V) {\n return transitionDigit(\n this.numberAdapter,\n this.numberAdapter.max(from, to),\n this.numberAdapter.min(from, to),\n this.partsOptions.sampleCount,\n );\n }\n\n // eslint-disable-next-line class-methods-use-this\n sampleSplit(samples: V[]) {\n return [samples.slice()];\n }\n\n sampleToString(value: V) {\n return this.numberAdapter.toString(value);\n }\n\n /**\n * 判断是否需要重新生成 parts 数据.\n *\n * {@link processPartData} 依赖 {@link partsOptions} 和 {@link value} 生成数据. 因此, 仅当依赖项变化时, 需要重新生成数据.\n *\n * @param changedProperties\n * @protected\n */\n // eslint-disable-next-line class-methods-use-this\n shouldRebuildParts(changedProperties: PropertyValues<this>): boolean {\n return (\n changedProperties.has('value') || changedProperties.has('partsOptions')\n );\n }\n\n override willUpdate(changedProperties: PropertyValues<this>) {\n super.willUpdate(changedProperties);\n\n if (changedProperties.has('value')) {\n this.oldParts = this.parts;\n }\n\n if (this.shouldRebuildParts(changedProperties)) {\n this.parts = this.processPartData();\n }\n\n if (changedProperties.has('value')) {\n this.partPreprocessDataList = preprocessPartData(\n this.direction,\n this.parts,\n this.oldDirection,\n this.oldParts,\n );\n }\n\n /**\n * `value` 没变但 `direction` 变化时, 也要重新生成 `partPreprocessDataList`.\n */\n // todo test events 和 animationOptions 冲突\n // if (\n // changedProperties.has('value') ||\n // changedProperties.has('direction')\n // ) {\n // }\n }\n\n /**\n * process:\n * 1. 采样\n * 2. 转换\n * 3. 构造\n */\n private processPartData() {\n const { decimalSeparator, digitToChar, minPlaces, fillChar, type } =\n this.partsOptions;\n\n const from = this.value;\n const to = this.oldValue;\n\n let _sampleToString: (value: V) => string[] = value =>\n this.sampleToString(value).split(decimalSeparator);\n if (type === 'string') {\n _sampleToString = value => [this.sampleToString(value), ''];\n }\n\n const result: PartData[] = [];\n\n /**\n * 对 {@link from} 到 {@link to} 的范围采样.\n */\n const tempParts = this.sampleSplit(this.sampling(from, to));\n\n /**\n * 将时间部分的数字转换为用于滚动的字符串数组\n *\n * headNumber: 最先显示的数字. 向下滚动时, 为滚动列表的最后一个数字, 向上滚动时相反.\n * tailNumber: 最后显示的数字. 向下滚动时, 为滚动列表的第一个数字, 向上滚动时相反.\n */\n {\n const directionValue = this.numberAdapter.gt(from, to) ? 'down' : 'up';\n for (let i = 0; i < tempParts.length; i++) {\n const partData = tempParts[i];\n // const headNumber =\n // partData[directionValue === \"down\" ? partData.length - 1 : 0];\n const tailNumber =\n partData[directionValue === 'down' ? 0 : partData.length - 1];\n\n const [minIntegerPlaces = 1, minDecimalPlaces = 0] = minPlaces;\n\n const numberParts = _sampleToString(tailNumber);\n const integerPlaces = Math.max(\n // numberParts[0].length,\n this.stringAdapter.stringToChars(numberParts[0]).length,\n minIntegerPlaces,\n );\n const decimalPlaces = Math.max(\n // numberParts[1]?.length ?? 0,\n this.stringAdapter.stringToChars(numberParts[1] ?? '').length,\n minDecimalPlaces,\n );\n\n /**\n * 使用 zip 将二维矩阵, 旋转90度\n */\n const data = zip(\n ...partData\n /**\n * 保证位数一致, 向前补零\n */\n .map(digitData => {\n const [integer = '', decimal = ''] = _sampleToString(digitData);\n\n const integerChars = this.stringAdapter.stringToChars(integer);\n const decimalChars = this.stringAdapter.stringToChars(decimal);\n\n const filledIntegerPlaces = Math.max(\n integerPlaces - integerChars.length,\n 0,\n );\n\n const filledDecimalPlaces = Math.max(\n decimalPlaces - decimalChars.length,\n 0,\n );\n\n let filledChars = ([] as string[]).concat(\n new Array(filledIntegerPlaces).fill(fillChar),\n integerChars,\n );\n if (decimalPlaces > 0) {\n filledChars = filledChars.concat(\n [decimalSeparator],\n decimalChars,\n new Array(filledDecimalPlaces).fill(fillChar),\n );\n }\n return filledChars;\n }),\n )\n /**\n * 删除连续的重复项\n */\n .map((digitList, index, array) => ({\n data: digitList\n .filter(\n (digit, digitIndex, digitArray) =>\n digitIndex === 0 || digit !== digitArray[digitIndex - 1],\n )\n .map(digit => digitToChar[digit] ?? digit),\n place: array.length - index,\n }));\n\n result.push({\n digits: data,\n });\n }\n }\n\n return result;\n }\n }\n\n return CounterPartsMixinClass as Constructor<CounterPartsMixinInterface<V>> &\n T;\n};\n"]}
@@ -7,7 +7,7 @@ export declare class TimeredCounterDatetimeDuration extends TimeredCounter {
7
7
  private __precision;
8
8
  /**
9
9
  * 计数器显示的精度.
10
- * 1. 当为单个值时, 表示最小精度.
10
+ * 1. 当为单个值时, 仅显示该精度的时间部分.
11
11
  * 2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.
12
12
  *
13
13
  * @default [DurationPartType.Second, DurationPartType.Day]
@@ -41,6 +41,7 @@ export declare class TimeredCounterDatetimeDuration extends TimeredCounter {
41
41
  sampleSplit(samples: AvailableNumberAdapterValueType[]): AvailableNumberAdapterValueType[][];
42
42
  generateAriaLabel(): string;
43
43
  connectedCallback(): void;
44
+ shouldRebuildParts(changedProperties: PropertyValues<this>): boolean;
44
45
  willUpdate(_changedProperties: PropertyValues): void;
45
46
  render(): import("lit-html").TemplateResult<1>;
46
47
  }
@@ -15,20 +15,14 @@ import { parseJsonString } from './utils/parse-json-string.js';
15
15
  * 根据最小精度对 from 进行优化. 避免频繁更新.
16
16
  *
17
17
  * 1. from 先会被减小到 minPrecisionMs 的整数倍.
18
- * 2. 如果 from 和 to 的差值不是 minPrecisionMs 的整数倍, 则再加上/减去一个 minPrecisionMs 的值. 加上或减去取决于 from to 的谁更大.
19
- * 这相当于将 from 中小于 minPrecisionMs 的值舍入到 minPrecisionMs 的整数倍.
20
- * 3. 加上 to 余 minPrecisionMs 的值, 保证 from 与 to 的差值是 minPrecisionMs 的整数倍.
18
+ * 2. 加上 to minPrecisionMs 的值, 保证 from to 的差值是 minPrecisionMs 的整数倍.
21
19
  */
22
20
  function optimizeFrom(from, to, minPrecision) {
23
21
  const minPrecisionMs = DurationPartMillisecond[minPrecision];
24
22
  const fromTS = from.getTime();
25
23
  const toTS = to.getTime();
26
24
  const base = fromTS - (fromTS % minPrecisionMs);
27
- const offset = Math.abs(toTS - fromTS) % minPrecisionMs;
28
- return (base +
29
- (offset > 0 ? (fromTS < toTS ? -1 : 1) * minPrecisionMs : 0) +
30
- // 加上 deadlineDate 的余数, 消除精度误差.
31
- (toTS % minPrecisionMs));
25
+ return base + (toTS % minPrecisionMs);
32
26
  }
33
27
  function toDurationInMilliseconds(value, minPrecision) {
34
28
  if (isString(value))
@@ -64,7 +58,7 @@ let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extend
64
58
  }
65
59
  /**
66
60
  * 计数器显示的精度.
67
- * 1. 当为单个值时, 表示最小精度.
61
+ * 1. 当为单个值时, 仅显示该精度的时间部分.
68
62
  * 2. 当为数组时, 第一个值表示最小精度, 第二个值表示最大精度.
69
63
  *
70
64
  * @default [DurationPartType.Second, DurationPartType.Day]
@@ -165,6 +159,10 @@ let TimeredCounterDatetimeDuration = class TimeredCounterDatetimeDuration extend
165
159
  this.precision = this.__precision;
166
160
  super.connectedCallback();
167
161
  }
162
+ shouldRebuildParts(changedProperties) {
163
+ return (super.shouldRebuildParts(changedProperties) ||
164
+ changedProperties.has('precision'));
165
+ }
168
166
  willUpdate(_changedProperties) {
169
167
  super.willUpdate(_changedProperties);
170
168
  if (_changedProperties.has('locale')) {