@ni/nimble-components 15.4.0 → 15.5.1

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.
@@ -2597,6 +2597,506 @@
2597
2597
  }
2598
2598
  }
2599
2599
 
2600
+ /** @internal */
2601
+ function newSplice(index, removed, addedCount) {
2602
+ return {
2603
+ index: index,
2604
+ removed: removed,
2605
+ addedCount: addedCount,
2606
+ };
2607
+ }
2608
+ const EDIT_LEAVE = 0;
2609
+ const EDIT_UPDATE = 1;
2610
+ const EDIT_ADD = 2;
2611
+ const EDIT_DELETE = 3;
2612
+ // Note: This function is *based* on the computation of the Levenshtein
2613
+ // "edit" distance. The one change is that "updates" are treated as two
2614
+ // edits - not one. With Array splices, an update is really a delete
2615
+ // followed by an add. By retaining this, we optimize for "keeping" the
2616
+ // maximum array items in the original array. For example:
2617
+ //
2618
+ // 'xxxx123' -> '123yyyy'
2619
+ //
2620
+ // With 1-edit updates, the shortest path would be just to update all seven
2621
+ // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
2622
+ // leaves the substring '123' intact.
2623
+ function calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {
2624
+ // "Deletion" columns
2625
+ const rowCount = oldEnd - oldStart + 1;
2626
+ const columnCount = currentEnd - currentStart + 1;
2627
+ const distances = new Array(rowCount);
2628
+ let north;
2629
+ let west;
2630
+ // "Addition" rows. Initialize null column.
2631
+ for (let i = 0; i < rowCount; ++i) {
2632
+ distances[i] = new Array(columnCount);
2633
+ distances[i][0] = i;
2634
+ }
2635
+ // Initialize null row
2636
+ for (let j = 0; j < columnCount; ++j) {
2637
+ distances[0][j] = j;
2638
+ }
2639
+ for (let i = 1; i < rowCount; ++i) {
2640
+ for (let j = 1; j < columnCount; ++j) {
2641
+ if (current[currentStart + j - 1] === old[oldStart + i - 1]) {
2642
+ distances[i][j] = distances[i - 1][j - 1];
2643
+ }
2644
+ else {
2645
+ north = distances[i - 1][j] + 1;
2646
+ west = distances[i][j - 1] + 1;
2647
+ distances[i][j] = north < west ? north : west;
2648
+ }
2649
+ }
2650
+ }
2651
+ return distances;
2652
+ }
2653
+ // This starts at the final weight, and walks "backward" by finding
2654
+ // the minimum previous weight recursively until the origin of the weight
2655
+ // matrix.
2656
+ function spliceOperationsFromEditDistances(distances) {
2657
+ let i = distances.length - 1;
2658
+ let j = distances[0].length - 1;
2659
+ let current = distances[i][j];
2660
+ const edits = [];
2661
+ while (i > 0 || j > 0) {
2662
+ if (i === 0) {
2663
+ edits.push(EDIT_ADD);
2664
+ j--;
2665
+ continue;
2666
+ }
2667
+ if (j === 0) {
2668
+ edits.push(EDIT_DELETE);
2669
+ i--;
2670
+ continue;
2671
+ }
2672
+ const northWest = distances[i - 1][j - 1];
2673
+ const west = distances[i - 1][j];
2674
+ const north = distances[i][j - 1];
2675
+ let min;
2676
+ if (west < north) {
2677
+ min = west < northWest ? west : northWest;
2678
+ }
2679
+ else {
2680
+ min = north < northWest ? north : northWest;
2681
+ }
2682
+ if (min === northWest) {
2683
+ if (northWest === current) {
2684
+ edits.push(EDIT_LEAVE);
2685
+ }
2686
+ else {
2687
+ edits.push(EDIT_UPDATE);
2688
+ current = northWest;
2689
+ }
2690
+ i--;
2691
+ j--;
2692
+ }
2693
+ else if (min === west) {
2694
+ edits.push(EDIT_DELETE);
2695
+ i--;
2696
+ current = west;
2697
+ }
2698
+ else {
2699
+ edits.push(EDIT_ADD);
2700
+ j--;
2701
+ current = north;
2702
+ }
2703
+ }
2704
+ edits.reverse();
2705
+ return edits;
2706
+ }
2707
+ function sharedPrefix(current, old, searchLength) {
2708
+ for (let i = 0; i < searchLength; ++i) {
2709
+ if (current[i] !== old[i]) {
2710
+ return i;
2711
+ }
2712
+ }
2713
+ return searchLength;
2714
+ }
2715
+ function sharedSuffix(current, old, searchLength) {
2716
+ let index1 = current.length;
2717
+ let index2 = old.length;
2718
+ let count = 0;
2719
+ while (count < searchLength && current[--index1] === old[--index2]) {
2720
+ count++;
2721
+ }
2722
+ return count;
2723
+ }
2724
+ function intersect(start1, end1, start2, end2) {
2725
+ // Disjoint
2726
+ if (end1 < start2 || end2 < start1) {
2727
+ return -1;
2728
+ }
2729
+ // Adjacent
2730
+ if (end1 === start2 || end2 === start1) {
2731
+ return 0;
2732
+ }
2733
+ // Non-zero intersect, span1 first
2734
+ if (start1 < start2) {
2735
+ if (end1 < end2) {
2736
+ return end1 - start2; // Overlap
2737
+ }
2738
+ return end2 - start2; // Contained
2739
+ }
2740
+ // Non-zero intersect, span2 first
2741
+ if (end2 < end1) {
2742
+ return end2 - start1; // Overlap
2743
+ }
2744
+ return end1 - start1; // Contained
2745
+ }
2746
+ /**
2747
+ * Splice Projection functions:
2748
+ *
2749
+ * A splice map is a representation of how a previous array of items
2750
+ * was transformed into a new array of items. Conceptually it is a list of
2751
+ * tuples of
2752
+ *
2753
+ * <index, removed, addedCount>
2754
+ *
2755
+ * which are kept in ascending index order of. The tuple represents that at
2756
+ * the |index|, |removed| sequence of items were removed, and counting forward
2757
+ * from |index|, |addedCount| items were added.
2758
+ */
2759
+ /**
2760
+ * @internal
2761
+ * @remarks
2762
+ * Lacking individual splice mutation information, the minimal set of
2763
+ * splices can be synthesized given the previous state and final state of an
2764
+ * array. The basic approach is to calculate the edit distance matrix and
2765
+ * choose the shortest path through it.
2766
+ *
2767
+ * Complexity: O(l * p)
2768
+ * l: The length of the current array
2769
+ * p: The length of the old array
2770
+ */
2771
+ function calcSplices(current, currentStart, currentEnd, old, oldStart, oldEnd) {
2772
+ let prefixCount = 0;
2773
+ let suffixCount = 0;
2774
+ const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
2775
+ if (currentStart === 0 && oldStart === 0) {
2776
+ prefixCount = sharedPrefix(current, old, minLength);
2777
+ }
2778
+ if (currentEnd === current.length && oldEnd === old.length) {
2779
+ suffixCount = sharedSuffix(current, old, minLength - prefixCount);
2780
+ }
2781
+ currentStart += prefixCount;
2782
+ oldStart += prefixCount;
2783
+ currentEnd -= suffixCount;
2784
+ oldEnd -= suffixCount;
2785
+ if (currentEnd - currentStart === 0 && oldEnd - oldStart === 0) {
2786
+ return emptyArray;
2787
+ }
2788
+ if (currentStart === currentEnd) {
2789
+ const splice = newSplice(currentStart, [], 0);
2790
+ while (oldStart < oldEnd) {
2791
+ splice.removed.push(old[oldStart++]);
2792
+ }
2793
+ return [splice];
2794
+ }
2795
+ else if (oldStart === oldEnd) {
2796
+ return [newSplice(currentStart, [], currentEnd - currentStart)];
2797
+ }
2798
+ const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
2799
+ const splices = [];
2800
+ let splice = void 0;
2801
+ let index = currentStart;
2802
+ let oldIndex = oldStart;
2803
+ for (let i = 0; i < ops.length; ++i) {
2804
+ switch (ops[i]) {
2805
+ case EDIT_LEAVE:
2806
+ if (splice !== void 0) {
2807
+ splices.push(splice);
2808
+ splice = void 0;
2809
+ }
2810
+ index++;
2811
+ oldIndex++;
2812
+ break;
2813
+ case EDIT_UPDATE:
2814
+ if (splice === void 0) {
2815
+ splice = newSplice(index, [], 0);
2816
+ }
2817
+ splice.addedCount++;
2818
+ index++;
2819
+ splice.removed.push(old[oldIndex]);
2820
+ oldIndex++;
2821
+ break;
2822
+ case EDIT_ADD:
2823
+ if (splice === void 0) {
2824
+ splice = newSplice(index, [], 0);
2825
+ }
2826
+ splice.addedCount++;
2827
+ index++;
2828
+ break;
2829
+ case EDIT_DELETE:
2830
+ if (splice === void 0) {
2831
+ splice = newSplice(index, [], 0);
2832
+ }
2833
+ splice.removed.push(old[oldIndex]);
2834
+ oldIndex++;
2835
+ break;
2836
+ // no default
2837
+ }
2838
+ }
2839
+ if (splice !== void 0) {
2840
+ splices.push(splice);
2841
+ }
2842
+ return splices;
2843
+ }
2844
+ const $push = Array.prototype.push;
2845
+ function mergeSplice(splices, index, removed, addedCount) {
2846
+ const splice = newSplice(index, removed, addedCount);
2847
+ let inserted = false;
2848
+ let insertionOffset = 0;
2849
+ for (let i = 0; i < splices.length; i++) {
2850
+ const current = splices[i];
2851
+ current.index += insertionOffset;
2852
+ if (inserted) {
2853
+ continue;
2854
+ }
2855
+ const intersectCount = intersect(splice.index, splice.index + splice.removed.length, current.index, current.index + current.addedCount);
2856
+ if (intersectCount >= 0) {
2857
+ // Merge the two splices
2858
+ splices.splice(i, 1);
2859
+ i--;
2860
+ insertionOffset -= current.addedCount - current.removed.length;
2861
+ splice.addedCount += current.addedCount - intersectCount;
2862
+ const deleteCount = splice.removed.length + current.removed.length - intersectCount;
2863
+ if (!splice.addedCount && !deleteCount) {
2864
+ // merged splice is a noop. discard.
2865
+ inserted = true;
2866
+ }
2867
+ else {
2868
+ let currentRemoved = current.removed;
2869
+ if (splice.index < current.index) {
2870
+ // some prefix of splice.removed is prepended to current.removed.
2871
+ const prepend = splice.removed.slice(0, current.index - splice.index);
2872
+ $push.apply(prepend, currentRemoved);
2873
+ currentRemoved = prepend;
2874
+ }
2875
+ if (splice.index + splice.removed.length >
2876
+ current.index + current.addedCount) {
2877
+ // some suffix of splice.removed is appended to current.removed.
2878
+ const append = splice.removed.slice(current.index + current.addedCount - splice.index);
2879
+ $push.apply(currentRemoved, append);
2880
+ }
2881
+ splice.removed = currentRemoved;
2882
+ if (current.index < splice.index) {
2883
+ splice.index = current.index;
2884
+ }
2885
+ }
2886
+ }
2887
+ else if (splice.index < current.index) {
2888
+ // Insert splice here.
2889
+ inserted = true;
2890
+ splices.splice(i, 0, splice);
2891
+ i++;
2892
+ const offset = splice.addedCount - splice.removed.length;
2893
+ current.index += offset;
2894
+ insertionOffset += offset;
2895
+ }
2896
+ }
2897
+ if (!inserted) {
2898
+ splices.push(splice);
2899
+ }
2900
+ }
2901
+ function createInitialSplices(changeRecords) {
2902
+ const splices = [];
2903
+ for (let i = 0, ii = changeRecords.length; i < ii; i++) {
2904
+ const record = changeRecords[i];
2905
+ mergeSplice(splices, record.index, record.removed, record.addedCount);
2906
+ }
2907
+ return splices;
2908
+ }
2909
+ /** @internal */
2910
+ function projectArraySplices(array, changeRecords) {
2911
+ let splices = [];
2912
+ const initialSplices = createInitialSplices(changeRecords);
2913
+ for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
2914
+ const splice = initialSplices[i];
2915
+ if (splice.addedCount === 1 && splice.removed.length === 1) {
2916
+ if (splice.removed[0] !== array[splice.index]) {
2917
+ splices.push(splice);
2918
+ }
2919
+ continue;
2920
+ }
2921
+ splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
2922
+ }
2923
+ return splices;
2924
+ }
2925
+
2926
+ let arrayObservationEnabled = false;
2927
+ function adjustIndex(changeRecord, array) {
2928
+ let index = changeRecord.index;
2929
+ const arrayLength = array.length;
2930
+ if (index > arrayLength) {
2931
+ index = arrayLength - changeRecord.addedCount;
2932
+ }
2933
+ else if (index < 0) {
2934
+ index =
2935
+ arrayLength + changeRecord.removed.length + index - changeRecord.addedCount;
2936
+ }
2937
+ if (index < 0) {
2938
+ index = 0;
2939
+ }
2940
+ changeRecord.index = index;
2941
+ return changeRecord;
2942
+ }
2943
+ class ArrayObserver extends SubscriberSet {
2944
+ constructor(source) {
2945
+ super(source);
2946
+ this.oldCollection = void 0;
2947
+ this.splices = void 0;
2948
+ this.needsQueue = true;
2949
+ this.call = this.flush;
2950
+ Reflect.defineProperty(source, "$fastController", {
2951
+ value: this,
2952
+ enumerable: false,
2953
+ });
2954
+ }
2955
+ subscribe(subscriber) {
2956
+ this.flush();
2957
+ super.subscribe(subscriber);
2958
+ }
2959
+ addSplice(splice) {
2960
+ if (this.splices === void 0) {
2961
+ this.splices = [splice];
2962
+ }
2963
+ else {
2964
+ this.splices.push(splice);
2965
+ }
2966
+ if (this.needsQueue) {
2967
+ this.needsQueue = false;
2968
+ DOM.queueUpdate(this);
2969
+ }
2970
+ }
2971
+ reset(oldCollection) {
2972
+ this.oldCollection = oldCollection;
2973
+ if (this.needsQueue) {
2974
+ this.needsQueue = false;
2975
+ DOM.queueUpdate(this);
2976
+ }
2977
+ }
2978
+ flush() {
2979
+ const splices = this.splices;
2980
+ const oldCollection = this.oldCollection;
2981
+ if (splices === void 0 && oldCollection === void 0) {
2982
+ return;
2983
+ }
2984
+ this.needsQueue = true;
2985
+ this.splices = void 0;
2986
+ this.oldCollection = void 0;
2987
+ const finalSplices = oldCollection === void 0
2988
+ ? projectArraySplices(this.source, splices)
2989
+ : calcSplices(this.source, 0, this.source.length, oldCollection, 0, oldCollection.length);
2990
+ this.notify(finalSplices);
2991
+ }
2992
+ }
2993
+ /* eslint-disable prefer-rest-params */
2994
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
2995
+ /**
2996
+ * Enables the array observation mechanism.
2997
+ * @remarks
2998
+ * Array observation is enabled automatically when using the
2999
+ * {@link RepeatDirective}, so calling this API manually is
3000
+ * not typically necessary.
3001
+ * @public
3002
+ */
3003
+ function enableArrayObservation() {
3004
+ if (arrayObservationEnabled) {
3005
+ return;
3006
+ }
3007
+ arrayObservationEnabled = true;
3008
+ Observable.setArrayObserverFactory((collection) => {
3009
+ return new ArrayObserver(collection);
3010
+ });
3011
+ const proto = Array.prototype;
3012
+ // Don't patch Array if it has already been patched
3013
+ // by another copy of fast-element.
3014
+ if (proto.$fastPatch) {
3015
+ return;
3016
+ }
3017
+ Reflect.defineProperty(proto, "$fastPatch", {
3018
+ value: 1,
3019
+ enumerable: false,
3020
+ });
3021
+ const pop = proto.pop;
3022
+ const push = proto.push;
3023
+ const reverse = proto.reverse;
3024
+ const shift = proto.shift;
3025
+ const sort = proto.sort;
3026
+ const splice = proto.splice;
3027
+ const unshift = proto.unshift;
3028
+ proto.pop = function () {
3029
+ const notEmpty = this.length > 0;
3030
+ const methodCallResult = pop.apply(this, arguments);
3031
+ const o = this.$fastController;
3032
+ if (o !== void 0 && notEmpty) {
3033
+ o.addSplice(newSplice(this.length, [methodCallResult], 0));
3034
+ }
3035
+ return methodCallResult;
3036
+ };
3037
+ proto.push = function () {
3038
+ const methodCallResult = push.apply(this, arguments);
3039
+ const o = this.$fastController;
3040
+ if (o !== void 0) {
3041
+ o.addSplice(adjustIndex(newSplice(this.length - arguments.length, [], arguments.length), this));
3042
+ }
3043
+ return methodCallResult;
3044
+ };
3045
+ proto.reverse = function () {
3046
+ let oldArray;
3047
+ const o = this.$fastController;
3048
+ if (o !== void 0) {
3049
+ o.flush();
3050
+ oldArray = this.slice();
3051
+ }
3052
+ const methodCallResult = reverse.apply(this, arguments);
3053
+ if (o !== void 0) {
3054
+ o.reset(oldArray);
3055
+ }
3056
+ return methodCallResult;
3057
+ };
3058
+ proto.shift = function () {
3059
+ const notEmpty = this.length > 0;
3060
+ const methodCallResult = shift.apply(this, arguments);
3061
+ const o = this.$fastController;
3062
+ if (o !== void 0 && notEmpty) {
3063
+ o.addSplice(newSplice(0, [methodCallResult], 0));
3064
+ }
3065
+ return methodCallResult;
3066
+ };
3067
+ proto.sort = function () {
3068
+ let oldArray;
3069
+ const o = this.$fastController;
3070
+ if (o !== void 0) {
3071
+ o.flush();
3072
+ oldArray = this.slice();
3073
+ }
3074
+ const methodCallResult = sort.apply(this, arguments);
3075
+ if (o !== void 0) {
3076
+ o.reset(oldArray);
3077
+ }
3078
+ return methodCallResult;
3079
+ };
3080
+ proto.splice = function () {
3081
+ const methodCallResult = splice.apply(this, arguments);
3082
+ const o = this.$fastController;
3083
+ if (o !== void 0) {
3084
+ o.addSplice(adjustIndex(newSplice(+arguments[0], methodCallResult, arguments.length > 2 ? arguments.length - 2 : 0), this));
3085
+ }
3086
+ return methodCallResult;
3087
+ };
3088
+ proto.unshift = function () {
3089
+ const methodCallResult = unshift.apply(this, arguments);
3090
+ const o = this.$fastController;
3091
+ if (o !== void 0) {
3092
+ o.addSplice(adjustIndex(newSplice(0, [], arguments.length), this));
3093
+ }
3094
+ return methodCallResult;
3095
+ };
3096
+ }
3097
+ /* eslint-enable prefer-rest-params */
3098
+ /* eslint-enable @typescript-eslint/explicit-function-return-type */
3099
+
2600
3100
  /**
2601
3101
  * The runtime behavior for template references.
2602
3102
  * @public
@@ -2649,6 +3149,267 @@
2649
3149
  return (source, context) => binding(source, context) ? getTemplate(source, context) : null;
2650
3150
  }
2651
3151
 
3152
+ const defaultRepeatOptions = Object.freeze({
3153
+ positioning: false,
3154
+ recycle: true,
3155
+ });
3156
+ function bindWithoutPositioning(view, items, index, context) {
3157
+ view.bind(items[index], context);
3158
+ }
3159
+ function bindWithPositioning(view, items, index, context) {
3160
+ const childContext = Object.create(context);
3161
+ childContext.index = index;
3162
+ childContext.length = items.length;
3163
+ view.bind(items[index], childContext);
3164
+ }
3165
+ /**
3166
+ * A behavior that renders a template for each item in an array.
3167
+ * @public
3168
+ */
3169
+ class RepeatBehavior {
3170
+ /**
3171
+ * Creates an instance of RepeatBehavior.
3172
+ * @param location - The location in the DOM to render the repeat.
3173
+ * @param itemsBinding - The array to render.
3174
+ * @param isItemsBindingVolatile - Indicates whether the items binding has volatile dependencies.
3175
+ * @param templateBinding - The template to render for each item.
3176
+ * @param isTemplateBindingVolatile - Indicates whether the template binding has volatile dependencies.
3177
+ * @param options - Options used to turn on special repeat features.
3178
+ */
3179
+ constructor(location, itemsBinding, isItemsBindingVolatile, templateBinding, isTemplateBindingVolatile, options) {
3180
+ this.location = location;
3181
+ this.itemsBinding = itemsBinding;
3182
+ this.templateBinding = templateBinding;
3183
+ this.options = options;
3184
+ this.source = null;
3185
+ this.views = [];
3186
+ this.items = null;
3187
+ this.itemsObserver = null;
3188
+ this.originalContext = void 0;
3189
+ this.childContext = void 0;
3190
+ this.bindView = bindWithoutPositioning;
3191
+ this.itemsBindingObserver = Observable.binding(itemsBinding, this, isItemsBindingVolatile);
3192
+ this.templateBindingObserver = Observable.binding(templateBinding, this, isTemplateBindingVolatile);
3193
+ if (options.positioning) {
3194
+ this.bindView = bindWithPositioning;
3195
+ }
3196
+ }
3197
+ /**
3198
+ * Bind this behavior to the source.
3199
+ * @param source - The source to bind to.
3200
+ * @param context - The execution context that the binding is operating within.
3201
+ */
3202
+ bind(source, context) {
3203
+ this.source = source;
3204
+ this.originalContext = context;
3205
+ this.childContext = Object.create(context);
3206
+ this.childContext.parent = source;
3207
+ this.childContext.parentContext = this.originalContext;
3208
+ this.items = this.itemsBindingObserver.observe(source, this.originalContext);
3209
+ this.template = this.templateBindingObserver.observe(source, this.originalContext);
3210
+ this.observeItems(true);
3211
+ this.refreshAllViews();
3212
+ }
3213
+ /**
3214
+ * Unbinds this behavior from the source.
3215
+ * @param source - The source to unbind from.
3216
+ */
3217
+ unbind() {
3218
+ this.source = null;
3219
+ this.items = null;
3220
+ if (this.itemsObserver !== null) {
3221
+ this.itemsObserver.unsubscribe(this);
3222
+ }
3223
+ this.unbindAllViews();
3224
+ this.itemsBindingObserver.disconnect();
3225
+ this.templateBindingObserver.disconnect();
3226
+ }
3227
+ /** @internal */
3228
+ handleChange(source, args) {
3229
+ if (source === this.itemsBinding) {
3230
+ this.items = this.itemsBindingObserver.observe(this.source, this.originalContext);
3231
+ this.observeItems();
3232
+ this.refreshAllViews();
3233
+ }
3234
+ else if (source === this.templateBinding) {
3235
+ this.template = this.templateBindingObserver.observe(this.source, this.originalContext);
3236
+ this.refreshAllViews(true);
3237
+ }
3238
+ else {
3239
+ this.updateViews(args);
3240
+ }
3241
+ }
3242
+ observeItems(force = false) {
3243
+ if (!this.items) {
3244
+ this.items = emptyArray;
3245
+ return;
3246
+ }
3247
+ const oldObserver = this.itemsObserver;
3248
+ const newObserver = (this.itemsObserver = Observable.getNotifier(this.items));
3249
+ const hasNewObserver = oldObserver !== newObserver;
3250
+ if (hasNewObserver && oldObserver !== null) {
3251
+ oldObserver.unsubscribe(this);
3252
+ }
3253
+ if (hasNewObserver || force) {
3254
+ newObserver.subscribe(this);
3255
+ }
3256
+ }
3257
+ updateViews(splices) {
3258
+ const childContext = this.childContext;
3259
+ const views = this.views;
3260
+ const bindView = this.bindView;
3261
+ const items = this.items;
3262
+ const template = this.template;
3263
+ const recycle = this.options.recycle;
3264
+ const leftoverViews = [];
3265
+ let leftoverIndex = 0;
3266
+ let availableViews = 0;
3267
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
3268
+ const splice = splices[i];
3269
+ const removed = splice.removed;
3270
+ let removeIndex = 0;
3271
+ let addIndex = splice.index;
3272
+ const end = addIndex + splice.addedCount;
3273
+ const removedViews = views.splice(splice.index, removed.length);
3274
+ const totalAvailableViews = (availableViews =
3275
+ leftoverViews.length + removedViews.length);
3276
+ for (; addIndex < end; ++addIndex) {
3277
+ const neighbor = views[addIndex];
3278
+ const location = neighbor ? neighbor.firstChild : this.location;
3279
+ let view;
3280
+ if (recycle && availableViews > 0) {
3281
+ if (removeIndex <= totalAvailableViews && removedViews.length > 0) {
3282
+ view = removedViews[removeIndex];
3283
+ removeIndex++;
3284
+ }
3285
+ else {
3286
+ view = leftoverViews[leftoverIndex];
3287
+ leftoverIndex++;
3288
+ }
3289
+ availableViews--;
3290
+ }
3291
+ else {
3292
+ view = template.create();
3293
+ }
3294
+ views.splice(addIndex, 0, view);
3295
+ bindView(view, items, addIndex, childContext);
3296
+ view.insertBefore(location);
3297
+ }
3298
+ if (removedViews[removeIndex]) {
3299
+ leftoverViews.push(...removedViews.slice(removeIndex));
3300
+ }
3301
+ }
3302
+ for (let i = leftoverIndex, ii = leftoverViews.length; i < ii; ++i) {
3303
+ leftoverViews[i].dispose();
3304
+ }
3305
+ if (this.options.positioning) {
3306
+ for (let i = 0, ii = views.length; i < ii; ++i) {
3307
+ const currentContext = views[i].context;
3308
+ currentContext.length = ii;
3309
+ currentContext.index = i;
3310
+ }
3311
+ }
3312
+ }
3313
+ refreshAllViews(templateChanged = false) {
3314
+ const items = this.items;
3315
+ const childContext = this.childContext;
3316
+ const template = this.template;
3317
+ const location = this.location;
3318
+ const bindView = this.bindView;
3319
+ let itemsLength = items.length;
3320
+ let views = this.views;
3321
+ let viewsLength = views.length;
3322
+ if (itemsLength === 0 || templateChanged || !this.options.recycle) {
3323
+ // all views need to be removed
3324
+ HTMLView.disposeContiguousBatch(views);
3325
+ viewsLength = 0;
3326
+ }
3327
+ if (viewsLength === 0) {
3328
+ // all views need to be created
3329
+ this.views = views = new Array(itemsLength);
3330
+ for (let i = 0; i < itemsLength; ++i) {
3331
+ const view = template.create();
3332
+ bindView(view, items, i, childContext);
3333
+ views[i] = view;
3334
+ view.insertBefore(location);
3335
+ }
3336
+ }
3337
+ else {
3338
+ // attempt to reuse existing views with new data
3339
+ let i = 0;
3340
+ for (; i < itemsLength; ++i) {
3341
+ if (i < viewsLength) {
3342
+ const view = views[i];
3343
+ bindView(view, items, i, childContext);
3344
+ }
3345
+ else {
3346
+ const view = template.create();
3347
+ bindView(view, items, i, childContext);
3348
+ views.push(view);
3349
+ view.insertBefore(location);
3350
+ }
3351
+ }
3352
+ const removed = views.splice(i, viewsLength - i);
3353
+ for (i = 0, itemsLength = removed.length; i < itemsLength; ++i) {
3354
+ removed[i].dispose();
3355
+ }
3356
+ }
3357
+ }
3358
+ unbindAllViews() {
3359
+ const views = this.views;
3360
+ for (let i = 0, ii = views.length; i < ii; ++i) {
3361
+ views[i].unbind();
3362
+ }
3363
+ }
3364
+ }
3365
+ /**
3366
+ * A directive that configures list rendering.
3367
+ * @public
3368
+ */
3369
+ class RepeatDirective extends HTMLDirective {
3370
+ /**
3371
+ * Creates an instance of RepeatDirective.
3372
+ * @param itemsBinding - The binding that provides the array to render.
3373
+ * @param templateBinding - The template binding used to obtain a template to render for each item in the array.
3374
+ * @param options - Options used to turn on special repeat features.
3375
+ */
3376
+ constructor(itemsBinding, templateBinding, options) {
3377
+ super();
3378
+ this.itemsBinding = itemsBinding;
3379
+ this.templateBinding = templateBinding;
3380
+ this.options = options;
3381
+ /**
3382
+ * Creates a placeholder string based on the directive's index within the template.
3383
+ * @param index - The index of the directive within the template.
3384
+ */
3385
+ this.createPlaceholder = DOM.createBlockPlaceholder;
3386
+ enableArrayObservation();
3387
+ this.isItemsBindingVolatile = Observable.isVolatileBinding(itemsBinding);
3388
+ this.isTemplateBindingVolatile = Observable.isVolatileBinding(templateBinding);
3389
+ }
3390
+ /**
3391
+ * Creates a behavior for the provided target node.
3392
+ * @param target - The node instance to create the behavior for.
3393
+ */
3394
+ createBehavior(target) {
3395
+ return new RepeatBehavior(target, this.itemsBinding, this.isItemsBindingVolatile, this.templateBinding, this.isTemplateBindingVolatile, this.options);
3396
+ }
3397
+ }
3398
+ /**
3399
+ * A directive that enables list rendering.
3400
+ * @param itemsBinding - The array to render.
3401
+ * @param templateOrTemplateBinding - The template or a template binding used obtain a template
3402
+ * to render for each item in the array.
3403
+ * @param options - Options used to turn on special repeat features.
3404
+ * @public
3405
+ */
3406
+ function repeat(itemsBinding, templateOrTemplateBinding, options = defaultRepeatOptions) {
3407
+ const templateBinding = typeof templateOrTemplateBinding === "function"
3408
+ ? templateOrTemplateBinding
3409
+ : () => templateOrTemplateBinding;
3410
+ return new RepeatDirective(itemsBinding, templateBinding, Object.assign(Object.assign({}, defaultRepeatOptions), options));
3411
+ }
3412
+
2652
3413
  /**
2653
3414
  * Creates a function that can be used to filter a Node array, selecting only elements.
2654
3415
  * @param selector - An optional selector to restrict the filter to.
@@ -14927,7 +15688,7 @@
14927
15688
  const prefix = 'ni-nimble';
14928
15689
  const styleNameFromTokenName = (tokenName) => `${prefix}-${tokenName}`;
14929
15690
 
14930
- const template$8 = html `<slot></slot>`;
15691
+ const template$9 = html `<slot></slot>`;
14931
15692
 
14932
15693
  const styles$x = css `
14933
15694
  :host {
@@ -14986,7 +15747,7 @@
14986
15747
  const nimbleDesignSystemProvider = ThemeProvider.compose({
14987
15748
  baseName: 'theme-provider',
14988
15749
  styles: styles$x,
14989
- template: template$8
15750
+ template: template$9
14990
15751
  });
14991
15752
  DesignSystem.getOrCreate()
14992
15753
  .withPrefix('nimble')
@@ -16704,7 +17465,7 @@
16704
17465
  }
16705
17466
  `;
16706
17467
 
16707
- const template$7 = (context, definition) => html `
17468
+ const template$8 = (context, definition) => html `
16708
17469
  <div
16709
17470
  role="button"
16710
17471
  part="control"
@@ -16779,7 +17540,7 @@
16779
17540
  applyMixins(ToggleButton, StartEnd, DelegatesARIAButton);
16780
17541
  const nimbleToggleButton = ToggleButton.compose({
16781
17542
  baseName: 'toggle-button',
16782
- template: template$7,
17543
+ template: template$8,
16783
17544
  styles: styles$q,
16784
17545
  shadowOptions: {
16785
17546
  delegatesFocus: true
@@ -16793,7 +17554,7 @@
16793
17554
  </div>
16794
17555
  `;
16795
17556
 
16796
- const template$6 = html `
17557
+ const template$7 = html `
16797
17558
  <template>
16798
17559
  <div class="icon" :innerHTML=${x => x.icon.data}></div>
16799
17560
  </template
@@ -16852,7 +17613,7 @@
16852
17613
  const registerIcon = (baseName, iconClass) => {
16853
17614
  const composedIcon = iconClass.compose({
16854
17615
  baseName,
16855
- template: template$6,
17616
+ template: template$7,
16856
17617
  styles: styles$p,
16857
17618
  baseClass: iconClass
16858
17619
  });
@@ -17551,7 +18312,7 @@
17551
18312
  }
17552
18313
  `));
17553
18314
 
17554
- const template$5 = html `
18315
+ const template$6 = html `
17555
18316
  <template>
17556
18317
  <dialog
17557
18318
  ${ref('dialogElement')}
@@ -17677,7 +18438,7 @@
17677
18438
  applyMixins(Dialog, ARIAGlobalStatesAndProperties);
17678
18439
  const nimbleDialog = Dialog.compose({
17679
18440
  baseName: 'dialog',
17680
- template: template$5,
18441
+ template: template$6,
17681
18442
  styles: styles$l,
17682
18443
  baseClass: Dialog
17683
18444
  });
@@ -17838,7 +18599,7 @@
17838
18599
  }
17839
18600
  `));
17840
18601
 
17841
- const template$4 = html `
18602
+ const template$5 = html `
17842
18603
  <dialog
17843
18604
  ${ref('dialog')}
17844
18605
  aria-label="${x => x.ariaLabel}"
@@ -17952,7 +18713,7 @@
17952
18713
  applyMixins(Drawer, ARIAGlobalStatesAndProperties);
17953
18714
  const nimbleDrawer = Drawer.compose({
17954
18715
  baseName: 'drawer',
17955
- template: template$4,
18716
+ template: template$5,
17956
18717
  styles: styles$k
17957
18718
  });
17958
18719
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleDrawer());
@@ -19747,7 +20508,7 @@
19747
20508
  `;
19748
20509
 
19749
20510
  // prettier-ignore
19750
- const template$3 = html `
20511
+ const template$4 = html `
19751
20512
  <template
19752
20513
  ?open="${x => x.open}"
19753
20514
  @focusout="${(x, c) => x.focusoutHandler(c.event)}"
@@ -19955,7 +20716,7 @@
19955
20716
  ], MenuButton.prototype, "slottedMenus", void 0);
19956
20717
  const nimbleMenuButton = MenuButton.compose({
19957
20718
  baseName: 'menu-button',
19958
- template: template$3,
20719
+ template: template$4,
19959
20720
  styles: styles$h,
19960
20721
  shadowOptions: {
19961
20722
  delegatesFocus: true
@@ -20732,7 +21493,7 @@
20732
21493
  `));
20733
21494
 
20734
21495
  // prettier-ignore
20735
- const template$2 = html `
21496
+ const template$3 = html `
20736
21497
  <template
20737
21498
  role="switch"
20738
21499
  aria-checked="${x => x.checked}"
@@ -20776,7 +21537,7 @@
20776
21537
  const nimbleSwitch = Switch.compose({
20777
21538
  baseClass: Switch$1,
20778
21539
  baseName: 'switch',
20779
- template: template$2,
21540
+ template: template$3,
20780
21541
  styles: styles$b
20781
21542
  });
20782
21543
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleSwitch());
@@ -20975,7 +21736,7 @@
20975
21736
  }
20976
21737
  `;
20977
21738
 
20978
- const template$1 = html `
21739
+ const template$2 = html `
20979
21740
  <template slot="end">
20980
21741
  <div class="separator"></div>
20981
21742
  <slot></slot>
@@ -20989,7 +21750,7 @@
20989
21750
  }
20990
21751
  const nimbleTabsToolbar = TabsToolbar.compose({
20991
21752
  baseName: 'tabs-toolbar',
20992
- template: template$1,
21753
+ template: template$2,
20993
21754
  styles: styles$7
20994
21755
  });
20995
21756
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleTabsToolbar());
@@ -21564,7 +22325,7 @@
21564
22325
  `));
21565
22326
 
21566
22327
  // prettier-ignore
21567
- const template = html `
22328
+ const template$1 = html `
21568
22329
  ${when(x => x.tooltipVisible, html `
21569
22330
  <${DesignSystem.tagFor(AnchoredRegion)}
21570
22331
  class="anchored-region"
@@ -21616,7 +22377,7 @@
21616
22377
  const nimbleTooltip = Tooltip.compose({
21617
22378
  baseName: 'tooltip',
21618
22379
  baseClass: Tooltip$1,
21619
- template,
22380
+ template: template$1,
21620
22381
  styles: styles$3
21621
22382
  });
21622
22383
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleTooltip());
@@ -22047,6 +22808,18 @@ Instead styling against the role which is more general and likely a better appro
22047
22808
  });
22048
22809
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleTreeView());
22049
22810
 
22811
+ // prettier-ignore
22812
+ const template = html `
22813
+ <div>
22814
+ <ul>
22815
+ ${repeat(x => x.dies, html ` <li>
22816
+ ${x => html `dieX: ${x.x}, dieY: ${x.y}, value:
22817
+ ${x.value}%`}
22818
+ </li>`)}
22819
+ </ul>
22820
+ </div>
22821
+ `;
22822
+
22050
22823
  const styles = css ``;
22051
22824
 
22052
22825
  const WaferMapQuadrant = {
@@ -22125,7 +22898,7 @@ Instead styling against the role which is more general and likely a better appro
22125
22898
  ], WaferMap.prototype, "colorScale", void 0);
22126
22899
  const nimbleWaferMap = WaferMap.compose({
22127
22900
  baseName: 'wafer-map',
22128
- template: template$8,
22901
+ template,
22129
22902
  styles
22130
22903
  });
22131
22904
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleWaferMap());