@fluidframework/tree 2.114.0 → 2.115.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.
- package/CHANGELOG.md +191 -0
- package/api-report/tree.alpha.api.md +108 -39
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/rebase/index.d.ts +1 -1
- package/dist/core/rebase/index.d.ts.map +1 -1
- package/dist/core/rebase/index.js +2 -1
- package/dist/core/rebase/index.js.map +1 -1
- package/dist/core/rebase/types.d.ts +110 -0
- package/dist/core/rebase/types.d.ts.map +1 -1
- package/dist/core/rebase/types.js +47 -1
- package/dist/core/rebase/types.js.map +1 -1
- package/dist/entrypoints/alpha.d.ts +1 -1
- package/dist/entrypoints/alpha.d.ts.map +1 -1
- package/dist/entrypoints/alpha.js +6 -4
- package/dist/entrypoints/alpha.js.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/codecs.d.ts +9 -6
- package/dist/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
- package/dist/feature-libraries/chunked-forest/codec/codecs.js +16 -13
- package/dist/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/shared-tree/sharedTree.d.ts +5 -0
- package/dist/shared-tree/sharedTree.d.ts.map +1 -1
- package/dist/shared-tree/sharedTree.js +1 -1
- package/dist/shared-tree/sharedTree.js.map +1 -1
- package/dist/shared-tree/treeCheckout.d.ts +5 -0
- package/dist/shared-tree/treeCheckout.d.ts.map +1 -1
- package/dist/shared-tree/treeCheckout.js +58 -12
- package/dist/shared-tree/treeCheckout.js.map +1 -1
- package/dist/shared-tree-core/branch.d.ts +1 -0
- package/dist/shared-tree-core/branch.d.ts.map +1 -1
- package/dist/shared-tree-core/branch.js.map +1 -1
- package/dist/shared-tree-core/sharedTreeCore.js +1 -1
- package/dist/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/dist/simple-tree/api/index.d.ts +1 -1
- package/dist/simple-tree/api/index.d.ts.map +1 -1
- package/dist/simple-tree/api/index.js +2 -3
- package/dist/simple-tree/api/index.js.map +1 -1
- package/dist/simple-tree/api/schemaFactoryAlpha.d.ts +3 -3
- package/dist/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaStatics.d.ts +6 -7
- package/dist/simple-tree/api/schemaStatics.d.ts.map +1 -1
- package/dist/simple-tree/api/schemaStatics.js.map +1 -1
- package/dist/simple-tree/api/treeNodeApi.d.ts +20 -24
- package/dist/simple-tree/api/treeNodeApi.d.ts.map +1 -1
- package/dist/simple-tree/api/treeNodeApi.js +48 -49
- package/dist/simple-tree/api/treeNodeApi.js.map +1 -1
- package/dist/simple-tree/core/treeNode.d.ts +5 -6
- package/dist/simple-tree/core/treeNode.d.ts.map +1 -1
- package/dist/simple-tree/core/treeNode.js +2 -4
- package/dist/simple-tree/core/treeNode.js.map +1 -1
- package/dist/simple-tree/core/withType.d.ts +20 -7
- package/dist/simple-tree/core/withType.d.ts.map +1 -1
- package/dist/simple-tree/core/withType.js +4 -7
- package/dist/simple-tree/core/withType.js.map +1 -1
- package/dist/simple-tree/index.d.ts +2 -2
- package/dist/simple-tree/index.d.ts.map +1 -1
- package/dist/simple-tree/index.js +3 -4
- package/dist/simple-tree/index.js.map +1 -1
- package/dist/simple-tree/leafNodeSchema.d.ts +6 -1
- package/dist/simple-tree/leafNodeSchema.d.ts.map +1 -1
- package/dist/simple-tree/leafNodeSchema.js +0 -1
- package/dist/simple-tree/leafNodeSchema.js.map +1 -1
- package/dist/simple-tree/node-kinds/array/arrayNode.d.ts +32 -3
- package/dist/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/array/arrayNode.js +91 -10
- package/dist/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.d.ts +77 -0
- package/dist/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
- package/dist/simple-tree/node-kinds/map/mapNode.js +17 -1
- package/dist/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/object/objectNode.js +2 -2
- package/dist/simple-tree/node-kinds/object/objectNode.js.map +1 -1
- package/dist/simple-tree/node-kinds/record/recordNode.js +2 -2
- package/dist/simple-tree/node-kinds/record/recordNode.js.map +1 -1
- package/dist/text/codePointUtils.d.ts +2 -2
- package/dist/text/codePointUtils.js +2 -2
- package/dist/text/codePointUtils.js.map +1 -1
- package/dist/text/index.d.ts +3 -3
- package/dist/text/index.d.ts.map +1 -1
- package/dist/text/index.js +4 -4
- package/dist/text/index.js.map +1 -1
- package/dist/text/textDomain.d.ts +18 -18
- package/dist/text/textDomain.d.ts.map +1 -1
- package/dist/text/textDomain.js +8 -8
- package/dist/text/textDomain.js.map +1 -1
- package/dist/text/textDomainFormatted.d.ts +46 -42
- package/dist/text/textDomainFormatted.d.ts.map +1 -1
- package/dist/text/textDomainFormatted.js +32 -28
- package/dist/text/textDomainFormatted.js.map +1 -1
- package/dist/text/textDomainFormattedDefault.d.ts +18 -18
- package/dist/text/textDomainFormattedDefault.d.ts.map +1 -1
- package/dist/text/textDomainFormattedDefault.js +14 -17
- package/dist/text/textDomainFormattedDefault.js.map +1 -1
- package/dist/util/compressedIds.d.ts +22 -2
- package/dist/util/compressedIds.d.ts.map +1 -1
- package/dist/util/compressedIds.js +22 -1
- package/dist/util/compressedIds.js.map +1 -1
- package/lib/core/index.d.ts +1 -1
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +1 -1
- package/lib/core/index.js.map +1 -1
- package/lib/core/rebase/index.d.ts +1 -1
- package/lib/core/rebase/index.d.ts.map +1 -1
- package/lib/core/rebase/index.js +1 -1
- package/lib/core/rebase/index.js.map +1 -1
- package/lib/core/rebase/types.d.ts +110 -0
- package/lib/core/rebase/types.d.ts.map +1 -1
- package/lib/core/rebase/types.js +46 -0
- package/lib/core/rebase/types.js.map +1 -1
- package/lib/entrypoints/alpha.d.ts +1 -1
- package/lib/entrypoints/alpha.d.ts.map +1 -1
- package/lib/entrypoints/alpha.js +1 -1
- package/lib/entrypoints/alpha.js.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/codecs.d.ts +9 -6
- package/lib/feature-libraries/chunked-forest/codec/codecs.d.ts.map +1 -1
- package/lib/feature-libraries/chunked-forest/codec/codecs.js +16 -13
- package/lib/feature-libraries/chunked-forest/codec/codecs.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/shared-tree/sharedTree.d.ts +5 -0
- package/lib/shared-tree/sharedTree.d.ts.map +1 -1
- package/lib/shared-tree/sharedTree.js +1 -1
- package/lib/shared-tree/sharedTree.js.map +1 -1
- package/lib/shared-tree/treeCheckout.d.ts +5 -0
- package/lib/shared-tree/treeCheckout.d.ts.map +1 -1
- package/lib/shared-tree/treeCheckout.js +60 -14
- package/lib/shared-tree/treeCheckout.js.map +1 -1
- package/lib/shared-tree-core/branch.d.ts +1 -0
- package/lib/shared-tree-core/branch.d.ts.map +1 -1
- package/lib/shared-tree-core/branch.js.map +1 -1
- package/lib/shared-tree-core/sharedTreeCore.js +1 -1
- package/lib/shared-tree-core/sharedTreeCore.js.map +1 -1
- package/lib/simple-tree/api/index.d.ts +1 -1
- package/lib/simple-tree/api/index.d.ts.map +1 -1
- package/lib/simple-tree/api/index.js +1 -1
- package/lib/simple-tree/api/index.js.map +1 -1
- package/lib/simple-tree/api/schemaFactoryAlpha.d.ts +3 -3
- package/lib/simple-tree/api/schemaFactoryAlpha.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaStatics.d.ts +6 -7
- package/lib/simple-tree/api/schemaStatics.d.ts.map +1 -1
- package/lib/simple-tree/api/schemaStatics.js.map +1 -1
- package/lib/simple-tree/api/treeNodeApi.d.ts +20 -24
- package/lib/simple-tree/api/treeNodeApi.d.ts.map +1 -1
- package/lib/simple-tree/api/treeNodeApi.js +46 -46
- package/lib/simple-tree/api/treeNodeApi.js.map +1 -1
- package/lib/simple-tree/core/treeNode.d.ts +5 -6
- package/lib/simple-tree/core/treeNode.d.ts.map +1 -1
- package/lib/simple-tree/core/treeNode.js +2 -4
- package/lib/simple-tree/core/treeNode.js.map +1 -1
- package/lib/simple-tree/core/withType.d.ts +20 -7
- package/lib/simple-tree/core/withType.d.ts.map +1 -1
- package/lib/simple-tree/core/withType.js +4 -7
- package/lib/simple-tree/core/withType.js.map +1 -1
- package/lib/simple-tree/index.d.ts +2 -2
- package/lib/simple-tree/index.d.ts.map +1 -1
- package/lib/simple-tree/index.js +1 -1
- package/lib/simple-tree/index.js.map +1 -1
- package/lib/simple-tree/leafNodeSchema.d.ts +6 -1
- package/lib/simple-tree/leafNodeSchema.d.ts.map +1 -1
- package/lib/simple-tree/leafNodeSchema.js +0 -1
- package/lib/simple-tree/leafNodeSchema.js.map +1 -1
- package/lib/simple-tree/node-kinds/array/arrayNode.d.ts +32 -3
- package/lib/simple-tree/node-kinds/array/arrayNode.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/array/arrayNode.js +93 -12
- package/lib/simple-tree/node-kinds/array/arrayNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.d.ts +77 -0
- package/lib/simple-tree/node-kinds/map/mapNode.d.ts.map +1 -1
- package/lib/simple-tree/node-kinds/map/mapNode.js +18 -2
- package/lib/simple-tree/node-kinds/map/mapNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/object/objectNode.js +3 -3
- package/lib/simple-tree/node-kinds/object/objectNode.js.map +1 -1
- package/lib/simple-tree/node-kinds/record/recordNode.js +3 -3
- package/lib/simple-tree/node-kinds/record/recordNode.js.map +1 -1
- package/lib/text/codePointUtils.d.ts +2 -2
- package/lib/text/codePointUtils.js +2 -2
- package/lib/text/codePointUtils.js.map +1 -1
- package/lib/text/index.d.ts +3 -3
- package/lib/text/index.d.ts.map +1 -1
- package/lib/text/index.js +3 -3
- package/lib/text/index.js.map +1 -1
- package/lib/text/textDomain.d.ts +18 -18
- package/lib/text/textDomain.d.ts.map +1 -1
- package/lib/text/textDomain.js +7 -7
- package/lib/text/textDomain.js.map +1 -1
- package/lib/text/textDomainFormatted.d.ts +46 -42
- package/lib/text/textDomainFormatted.d.ts.map +1 -1
- package/lib/text/textDomainFormatted.js +31 -27
- package/lib/text/textDomainFormatted.js.map +1 -1
- package/lib/text/textDomainFormattedDefault.d.ts +18 -18
- package/lib/text/textDomainFormattedDefault.d.ts.map +1 -1
- package/lib/text/textDomainFormattedDefault.js +14 -17
- package/lib/text/textDomainFormattedDefault.js.map +1 -1
- package/lib/util/compressedIds.d.ts +22 -2
- package/lib/util/compressedIds.d.ts.map +1 -1
- package/lib/util/compressedIds.js +22 -1
- package/lib/util/compressedIds.js.map +1 -1
- package/package.json +29 -22
- package/src/core/index.ts +2 -0
- package/src/core/rebase/index.ts +2 -0
- package/src/core/rebase/types.ts +113 -0
- package/src/entrypoints/alpha.ts +10 -6
- package/src/feature-libraries/chunked-forest/codec/codecs.ts +17 -14
- package/src/index.ts +7 -4
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/sharedTree.ts +6 -1
- package/src/shared-tree/treeCheckout.ts +81 -14
- package/src/shared-tree-core/branch.ts +1 -0
- package/src/shared-tree-core/sharedTreeCore.ts +1 -1
- package/src/simple-tree/api/index.ts +0 -1
- package/src/simple-tree/api/schemaStatics.ts +2 -2
- package/src/simple-tree/api/treeNodeApi.ts +64 -48
- package/src/simple-tree/core/treeNode.ts +13 -10
- package/src/simple-tree/core/withType.ts +20 -7
- package/src/simple-tree/index.ts +1 -2
- package/src/simple-tree/leafNodeSchema.ts +6 -1
- package/src/simple-tree/node-kinds/array/arrayNode.ts +109 -14
- package/src/simple-tree/node-kinds/map/mapNode.ts +113 -3
- package/src/simple-tree/node-kinds/object/objectNode.ts +3 -3
- package/src/simple-tree/node-kinds/record/recordNode.ts +3 -3
- package/src/text/README.md +1 -1
- package/src/text/codePointUtils.ts +2 -2
- package/src/text/index.ts +3 -3
- package/src/text/textDomain.ts +21 -21
- package/src/text/textDomainFormatted.ts +56 -52
- package/src/text/textDomainFormattedDefault.ts +14 -23
- package/src/util/compressedIds.ts +36 -3
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { Lazy, oob, fail, assert } from "@fluidframework/core-utils/internal";
|
|
6
|
+
import { Lazy, oob, fail, assert, clamp } from "@fluidframework/core-utils/internal";
|
|
7
7
|
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
8
8
|
|
|
9
|
-
import { EmptyKey, ObjectNodeStoredSchema } from "../../../core/index.js";
|
|
9
|
+
import { EmptyKey, ObjectNodeStoredSchema, type DeltaMark } from "../../../core/index.js";
|
|
10
10
|
import type {
|
|
11
11
|
FlexibleFieldContent,
|
|
12
12
|
FlexTreeNode,
|
|
@@ -23,7 +23,7 @@ import type { NodeSchemaOptionsAlpha, System_Unsafe } from "../../api/index.js";
|
|
|
23
23
|
import {
|
|
24
24
|
CompatibilityLevel,
|
|
25
25
|
type WithType,
|
|
26
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
26
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to implement the deprecated typeNameSymbol API.
|
|
27
27
|
typeNameSymbol,
|
|
28
28
|
NodeKind,
|
|
29
29
|
type TreeNode,
|
|
@@ -1534,7 +1534,7 @@ export function arraySchema<
|
|
|
1534
1534
|
public static readonly persistedMetadata: JsonCompatibleReadOnlyObject | undefined =
|
|
1535
1535
|
persistedMetadata;
|
|
1536
1536
|
|
|
1537
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
1537
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to implement the deprecated typeNameSymbol API.
|
|
1538
1538
|
public get [typeNameSymbol](): TName {
|
|
1539
1539
|
return identifier;
|
|
1540
1540
|
}
|
|
@@ -1668,11 +1668,21 @@ export interface ArrayPlaceAnchor {
|
|
|
1668
1668
|
* The current index within the array that this anchor refers to.
|
|
1669
1669
|
* @remarks
|
|
1670
1670
|
* This value is updated as the array is edited in a way that depends on the specific anchor implementation.
|
|
1671
|
-
* This index
|
|
1671
|
+
* This index is a value from 0 to the current length of the array (inclusive).
|
|
1672
1672
|
* If used as the index to insert content into the array, this means it can point to any location in the array,
|
|
1673
1673
|
* including just after the last child.
|
|
1674
|
+
* @throws A {@link @fluidframework/telemetry-utils#UsageError} if the anchor has been {@link ArrayPlaceAnchor.dispose | disposed}.
|
|
1674
1675
|
*/
|
|
1675
1676
|
get index(): number;
|
|
1677
|
+
|
|
1678
|
+
/**
|
|
1679
|
+
* Stop tracking this anchor and release any resources it holds.
|
|
1680
|
+
* @remarks
|
|
1681
|
+
* Call this when the anchor is no longer needed (for example when a tracked cursor position is discarded).
|
|
1682
|
+
* Interacting with an anchor (including reading its properties) after it has been disposed is invalid and will throw.
|
|
1683
|
+
* Calling `dispose` more than once has no effect.
|
|
1684
|
+
*/
|
|
1685
|
+
dispose(): void;
|
|
1676
1686
|
}
|
|
1677
1687
|
|
|
1678
1688
|
/**
|
|
@@ -1690,9 +1700,29 @@ export interface ArrayPlaceAnchor {
|
|
|
1690
1700
|
* This is intended to track a location that might be used for an insertion point (for example in a text editor): future changes to its details should
|
|
1691
1701
|
* make it behave better for such uses.
|
|
1692
1702
|
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1703
|
+
* In rare cases the tracked index cannot be updated precisely and the anchor falls back to best-effort behavior:
|
|
1704
|
+
* it keeps reporting a valid in-bounds index, but that index may no longer correspond to the same logical position
|
|
1705
|
+
* as before the change (this can happen when an incremental delta is unavailable for a change, such as during a
|
|
1706
|
+
* schema change). Consumers that require an accurate position across such changes should re-derive it from their
|
|
1707
|
+
* own state rather than relying solely on this anchor.
|
|
1695
1708
|
* @privateRemarks
|
|
1709
|
+
* The index is maintained incrementally from the shallow (insert/remove) delta delivered by the array node's
|
|
1710
|
+
* `childrenChangedAfterBatch` event: inserts and removes before the anchor point shift it, while edits after it
|
|
1711
|
+
* (or a removal of the span it sits between) leave it in place. This keeps the anchor pinned to the gap between
|
|
1712
|
+
* children even when the child originally at its index is removed.
|
|
1713
|
+
*
|
|
1714
|
+
* The best-effort behavior noted in the public remarks is the no-delta path: when the composed delta is unavailable
|
|
1715
|
+
* (see {@link NodeChangedDataDelta.delta}), the exact shift is unknown so the index is only clamped back into range.
|
|
1716
|
+
* This is intentionally weak rather than reintroducing a per-edit O(n) snapshot of the array to diff old-vs-new
|
|
1717
|
+
* (which would defeat the point of delta-based tracking) for a case that is rare and, for this alpha API, acceptable
|
|
1718
|
+
* to degrade. A stronger fallback could instead let a consumer that already maintains the array contents re-seed the
|
|
1719
|
+
* anchor's position on this path, so it lives with the consumer that has the data instead of being duplicated here.
|
|
1720
|
+
*
|
|
1721
|
+
* TODO: The no-delta case above is one of several places whose behavior is limited by changes for which a composed
|
|
1722
|
+
* delta cannot be produced (see {@link NodeChangedDataDelta.delta}). The underlying eventing limitation should be
|
|
1723
|
+
* fixed so a delta is always available; when adding new code constrained by it, note it here (or track it centrally)
|
|
1724
|
+
* so the full set of affected call sites is known and can be prioritized.
|
|
1725
|
+
*
|
|
1696
1726
|
* When stabilized, this should probably become a method on {@link (TreeArrayNode:interface)}.
|
|
1697
1727
|
* Future versions of this should use rebaser / changeset logic to do a better job of tracking a location across removals or reinsertion.
|
|
1698
1728
|
* How this would work, especially for unhydrated nodes is not yet clear.
|
|
@@ -1702,17 +1732,82 @@ export function createArrayInsertionAnchor(
|
|
|
1702
1732
|
node: TreeArrayNode,
|
|
1703
1733
|
currentIndex: number,
|
|
1704
1734
|
): ArrayPlaceAnchor {
|
|
1735
|
+
// An out-of-range or non-integer index is a usage error. An index equal to the array length is valid
|
|
1736
|
+
// (it points just past the last child).
|
|
1705
1737
|
const field = getInnerNode(node).getBoxed(EmptyKey);
|
|
1706
|
-
|
|
1738
|
+
validateIndex(currentIndex, field, "createArrayInsertionAnchor", /* allowOnePastEnd */ true);
|
|
1739
|
+
let trackedIndex = currentIndex;
|
|
1740
|
+
|
|
1741
|
+
const kernel = getKernel(node);
|
|
1742
|
+
let off: (() => void) | undefined = kernel.events.on(
|
|
1743
|
+
"childrenChangedAfterBatch",
|
|
1744
|
+
({ fieldMarks }) => {
|
|
1745
|
+
const marks = fieldMarks.get(EmptyKey);
|
|
1746
|
+
// This event fires after the change is applied, so the field reflects the post-edit length.
|
|
1747
|
+
const length = getInnerNode(node).getBoxed(EmptyKey).length;
|
|
1748
|
+
if (marks === undefined) {
|
|
1749
|
+
// No-delta path: the composed delta is unavailable, so the exact shift is unknown. Keep the
|
|
1750
|
+
// index valid by clamping it to the current length (best-effort). See this function's
|
|
1751
|
+
// @privateRemarks for when this happens and why the fallback is intentionally weak.
|
|
1752
|
+
trackedIndex = clamp(trackedIndex, 0, length);
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
// Clamp defensively so a malformed or partial delta can never push the tracked index outside the
|
|
1756
|
+
// valid insertion range while the anchor is live (adjustIndexForArrayDelta has no final clamp).
|
|
1757
|
+
trackedIndex = clamp(adjustIndexForArrayDelta(trackedIndex, marks), 0, length);
|
|
1758
|
+
},
|
|
1759
|
+
);
|
|
1760
|
+
|
|
1707
1761
|
return {
|
|
1708
1762
|
get index() {
|
|
1709
|
-
if (
|
|
1710
|
-
|
|
1711
|
-
}
|
|
1712
|
-
if (child.parentField.parent !== field) {
|
|
1713
|
-
return field.length;
|
|
1763
|
+
if (off === undefined) {
|
|
1764
|
+
throw new UsageError("Cannot read the index of a disposed ArrayPlaceAnchor.");
|
|
1714
1765
|
}
|
|
1715
|
-
return
|
|
1766
|
+
return trackedIndex;
|
|
1767
|
+
},
|
|
1768
|
+
dispose() {
|
|
1769
|
+
off?.();
|
|
1770
|
+
off = undefined;
|
|
1716
1771
|
},
|
|
1717
1772
|
};
|
|
1718
1773
|
}
|
|
1774
|
+
|
|
1775
|
+
/**
|
|
1776
|
+
* Compute the new index of an {@link ArrayPlaceAnchor} after applying a shallow array delta.
|
|
1777
|
+
* @remarks
|
|
1778
|
+
* The marks cover the array's sequence field in order. `readPosition` walks the pre-edit array as the marks are
|
|
1779
|
+
* consumed while `index` stays fixed at the anchor's pre-edit location; comparing the two (both in pre-edit
|
|
1780
|
+
* coordinates) shifts `newIndex` to keep the anchor in the same gap between children as content is inserted or
|
|
1781
|
+
* removed around it. Each mark is a removal (`detach`), an insertion (`attach`), or a retain (neither); a mark may
|
|
1782
|
+
* carry both `detach` and `attach`, which is handled as a removal followed by an insertion. The per-mark behavior is
|
|
1783
|
+
* commented inline below.
|
|
1784
|
+
*/
|
|
1785
|
+
function adjustIndexForArrayDelta(index: number, marks: readonly DeltaMark[]): number {
|
|
1786
|
+
let readPosition = 0;
|
|
1787
|
+
let newIndex = index;
|
|
1788
|
+
for (const mark of marks) {
|
|
1789
|
+
// A removal consumes pre-edit content: if it lies entirely before the anchor it pulls the anchor left,
|
|
1790
|
+
// and if it contains the anchor's position the anchor collapses to the start of the removed span.
|
|
1791
|
+
if (mark.detach !== undefined) {
|
|
1792
|
+
const removeEnd = readPosition + mark.count;
|
|
1793
|
+
if (removeEnd <= index) {
|
|
1794
|
+
newIndex -= mark.count;
|
|
1795
|
+
} else if (readPosition < index) {
|
|
1796
|
+
newIndex -= index - readPosition;
|
|
1797
|
+
}
|
|
1798
|
+
readPosition += mark.count;
|
|
1799
|
+
}
|
|
1800
|
+
if (mark.attach !== undefined) {
|
|
1801
|
+
// Content inserted at or before the anchor pushes it right; inserting exactly at the anchor leaves the
|
|
1802
|
+
// anchor after the new content (insertion-point behavior). Inserted content is new, so it does not
|
|
1803
|
+
// advance the pre-edit read position.
|
|
1804
|
+
if (readPosition <= index) {
|
|
1805
|
+
newIndex += mark.count;
|
|
1806
|
+
}
|
|
1807
|
+
} else if (mark.detach === undefined) {
|
|
1808
|
+
// Retain: existing content that was neither inserted nor removed.
|
|
1809
|
+
readPosition += mark.count;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
return newIndex;
|
|
1813
|
+
}
|
|
@@ -22,14 +22,18 @@ import {
|
|
|
22
22
|
type JsonCompatibleReadOnlyObject,
|
|
23
23
|
type RestrictiveStringRecord,
|
|
24
24
|
} from "../../../util/index.js";
|
|
25
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
NodeSchemaOptionsAlpha,
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Referenced by TSDoc {@link} in this file.
|
|
28
|
+
RunTransactionParamsAlpha,
|
|
29
|
+
} from "../../api/index.js";
|
|
26
30
|
import {
|
|
27
31
|
CompatibilityLevel,
|
|
28
32
|
getKernel,
|
|
29
33
|
type InnerNode,
|
|
30
34
|
NodeKind,
|
|
31
35
|
type TreeNodeSchema,
|
|
32
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
36
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to implement the deprecated typeNameSymbol API.
|
|
33
37
|
typeNameSymbol,
|
|
34
38
|
type TreeNode,
|
|
35
39
|
typeSchemaSymbol,
|
|
@@ -180,6 +184,90 @@ export interface TreeMapNodeAlpha<T extends ImplicitAllowedTypes = ImplicitAllow
|
|
|
180
184
|
* even if some of those elements were not yet in the map when the edit was authored.
|
|
181
185
|
*/
|
|
182
186
|
clear(): void;
|
|
187
|
+
/**
|
|
188
|
+
* Returns the value at `key`, first inserting `fallbackValue` if this map has no entry for `key`.
|
|
189
|
+
*
|
|
190
|
+
* @param key - The key of the element to return or insert at.
|
|
191
|
+
* @param fallbackValue - The value to insert if `key` has no entry.
|
|
192
|
+
* @returns The value at `key`, which may be the provided `fallbackValue`
|
|
193
|
+
* if the map had no previous entry for `key`.
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
196
|
+
* The check for the presence of an existing entry with the given `key` is performed at the time the edit is authored.
|
|
197
|
+
* This has implications for the merge semantics of this operation:
|
|
198
|
+
*
|
|
199
|
+
* - If no entry is present for `key` at authoring time (thus leading to an insert)
|
|
200
|
+
* while a peer concurrently inserts a value for the same `key`,
|
|
201
|
+
* then the two inserts will race and the one that is sequenced second will overwrite the value inserted by the one
|
|
202
|
+
* that is sequenced first.
|
|
203
|
+
*
|
|
204
|
+
* - If an entry is present for `key` at authoring time (thus leading to no insert)
|
|
205
|
+
* while a peer concurrently deletes the entry for `key`,
|
|
206
|
+
* then the map will end up with no entry for `key` no matter how the two edits are sequenced.
|
|
207
|
+
*
|
|
208
|
+
* - If an entry is present for `key` at authoring time (thus leading to no insert)
|
|
209
|
+
* while a peer concurrently inserts a new entry for `key`,
|
|
210
|
+
* then the map will end up with the entry set by the peer no matter how the two edits are sequenced.
|
|
211
|
+
*
|
|
212
|
+
* These last two points mean that, upon sequencing of an edit made with this API,
|
|
213
|
+
* there is no guarantee that the entry for the given key will be the current one (if any) or the fallback one.
|
|
214
|
+
* If such a guarantee is important, then consider using {@link RunTransactionParamsAlpha.preconditions}
|
|
215
|
+
* to ensure the edit only applies when appropriate.
|
|
216
|
+
*
|
|
217
|
+
* This API is **not** equivalent to the following alternative:
|
|
218
|
+
*
|
|
219
|
+
* ```typescript
|
|
220
|
+
* map.set(key, map.get(key) ?? fallbackValue);
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* They differ in the following ways:
|
|
224
|
+
*
|
|
225
|
+
* - This API treats entries containing `null` values as populated.
|
|
226
|
+
* By contrast, the above alternative's usage of `??` means that a `null` entry is treated as equivalent to a missing entry.
|
|
227
|
+
*
|
|
228
|
+
* - This API only inserts/sets the entry for the given `key` when there is no current one.
|
|
229
|
+
* By contrast, the above alternative always performs an insert.
|
|
230
|
+
* That insert will throw an error for non-leaf types (objects, maps, arrays, and records) in cases where the entry
|
|
231
|
+
* is already populated, because inserting a node that was already inserted is not supported.
|
|
232
|
+
* It will always succeed for leaf types (number, string, boolean, null, and handle) since a new node is created
|
|
233
|
+
* from the value.
|
|
234
|
+
* Note that even in the cases where it does not throw,
|
|
235
|
+
* the `set` operation has the potential to overwrite entries that are concurrently inserted even when the map had
|
|
236
|
+
* an entry for `key`, which is not the case with this API.
|
|
237
|
+
*
|
|
238
|
+
* Avoid using this API to write a default value into the document when the application could instead return that
|
|
239
|
+
* default when reading a missing entry, which is much less costly.
|
|
240
|
+
* A more appropriate use of this API is when the value to be optionally inserted varies with the key.
|
|
241
|
+
*/
|
|
242
|
+
getOrInsert(
|
|
243
|
+
key: string,
|
|
244
|
+
fallbackValue: InsertableTreeNodeFromImplicitAllowedTypes<T>,
|
|
245
|
+
): TreeNodeFromImplicitAllowedTypes<T>;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Returns the value at `key`, first inserting the value produced by `callback` if this map has no entry for `key`.
|
|
249
|
+
*
|
|
250
|
+
* @param key - The key of the element to return or insert at.
|
|
251
|
+
* @param callback - Invoked with `key` to produce the value to insert if `key` has no entry.
|
|
252
|
+
* Not invoked if an entry is present.
|
|
253
|
+
* @returns The value at `key`, which may be the value produced by `callback`
|
|
254
|
+
* if the map had no previous entry for `key`.
|
|
255
|
+
*
|
|
256
|
+
* @remarks
|
|
257
|
+
* This API is equivalent to {@link TreeMapNodeAlpha.getOrInsert} except that the fallback value is computed lazily:
|
|
258
|
+
* `callback` is only invoked when the map has no entry for `key`.
|
|
259
|
+
* Prefer this API over {@link TreeMapNodeAlpha.getOrInsert} when producing the fallback value is expensive.
|
|
260
|
+
*
|
|
261
|
+
* The check for the presence of an existing entry with the given `key` is performed at the time the edit is authored.
|
|
262
|
+
* See {@link TreeMapNodeAlpha.getOrInsert} for the implications this has on the merge semantics of this operation.
|
|
263
|
+
*
|
|
264
|
+
* If `callback` throws, no edit is made and the error is propagated to the caller.
|
|
265
|
+
* If `callback` sets an entry for `key` in this map, that entry is overwritten with the value `callback` returned.
|
|
266
|
+
*/
|
|
267
|
+
getOrInsertComputed(
|
|
268
|
+
key: string,
|
|
269
|
+
callback: (key: string) => InsertableTreeNodeFromImplicitAllowedTypes<T>,
|
|
270
|
+
): TreeNodeFromImplicitAllowedTypes<T>;
|
|
183
271
|
}
|
|
184
272
|
|
|
185
273
|
// TreeMapNode is invariant over schema type, so for this handler to work with all schema, the only possible type for the schema is `any`.
|
|
@@ -261,6 +349,28 @@ abstract class CustomMapNodeBase<const T extends ImplicitAllowedTypes> extends T
|
|
|
261
349
|
this.editor(key).set(mapTree, field.length === 0);
|
|
262
350
|
return this;
|
|
263
351
|
}
|
|
352
|
+
public getOrInsert(
|
|
353
|
+
key: string,
|
|
354
|
+
fallbackValue: InsertableTreeNodeFromImplicitAllowedTypes<T>,
|
|
355
|
+
): TreeNodeFromImplicitAllowedTypes<T> {
|
|
356
|
+
const existing = this.get(key);
|
|
357
|
+
if (existing !== undefined) {
|
|
358
|
+
return existing;
|
|
359
|
+
}
|
|
360
|
+
this.set(key, fallbackValue);
|
|
361
|
+
return this.get(key);
|
|
362
|
+
}
|
|
363
|
+
public getOrInsertComputed(
|
|
364
|
+
key: string,
|
|
365
|
+
callback: (key: string) => InsertableTreeNodeFromImplicitAllowedTypes<T>,
|
|
366
|
+
): TreeNodeFromImplicitAllowedTypes<T> {
|
|
367
|
+
const existing = this.get(key);
|
|
368
|
+
if (existing !== undefined) {
|
|
369
|
+
return existing;
|
|
370
|
+
}
|
|
371
|
+
this.set(key, callback(key));
|
|
372
|
+
return this.get(key);
|
|
373
|
+
}
|
|
264
374
|
public get size(): number {
|
|
265
375
|
return count(this.innerNode.keys());
|
|
266
376
|
}
|
|
@@ -375,7 +485,7 @@ export function mapSchema<
|
|
|
375
485
|
public static readonly persistedMetadata: JsonCompatibleReadOnlyObject | undefined =
|
|
376
486
|
persistedMetadata;
|
|
377
487
|
|
|
378
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
488
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to implement the deprecated typeNameSymbol API.
|
|
379
489
|
public get [typeNameSymbol](): TName {
|
|
380
490
|
return identifier;
|
|
381
491
|
}
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
type TreeNodeSchema,
|
|
33
33
|
NodeKind,
|
|
34
34
|
type WithType,
|
|
35
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
35
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to handle the deprecated typeNameSymbol API.
|
|
36
36
|
typeNameSymbol,
|
|
37
37
|
typeSchemaSymbol,
|
|
38
38
|
type InternalTreeNode,
|
|
@@ -335,7 +335,7 @@ function createProxyHandler(
|
|
|
335
335
|
if (propertyKey === typeSchemaSymbol) {
|
|
336
336
|
return schema;
|
|
337
337
|
}
|
|
338
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
338
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to handle the deprecated typeNameSymbol API.
|
|
339
339
|
if (propertyKey === typeNameSymbol) {
|
|
340
340
|
return schema.identifier;
|
|
341
341
|
}
|
|
@@ -633,7 +633,7 @@ export function objectSchema<
|
|
|
633
633
|
public static readonly persistedMetadata: JsonCompatibleReadOnlyObject | undefined =
|
|
634
634
|
nodeOptions.persistedMetadata;
|
|
635
635
|
|
|
636
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
636
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to implement the deprecated typeNameSymbol API.
|
|
637
637
|
public get [typeNameSymbol](): TName {
|
|
638
638
|
return identifier;
|
|
639
639
|
}
|
|
@@ -17,7 +17,7 @@ import type { NodeSchemaOptionsAlpha } from "../../api/index.js";
|
|
|
17
17
|
import {
|
|
18
18
|
type TreeNodeSchema,
|
|
19
19
|
NodeKind,
|
|
20
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
20
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to handle the deprecated typeNameSymbol API.
|
|
21
21
|
typeNameSymbol,
|
|
22
22
|
typeSchemaSymbol,
|
|
23
23
|
type UnhydratedFlexTreeNode,
|
|
@@ -78,7 +78,7 @@ function createRecordNodeProxy(
|
|
|
78
78
|
case typeSchemaSymbol: {
|
|
79
79
|
return schema;
|
|
80
80
|
}
|
|
81
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
81
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to handle the deprecated typeNameSymbol API.
|
|
82
82
|
case typeNameSymbol: {
|
|
83
83
|
return schema.identifier;
|
|
84
84
|
}
|
|
@@ -370,7 +370,7 @@ export function recordSchema<
|
|
|
370
370
|
public static readonly persistedMetadata: JsonCompatibleReadOnlyObject | undefined =
|
|
371
371
|
persistedMetadata;
|
|
372
372
|
|
|
373
|
-
// eslint-disable-next-line import-x/no-deprecated
|
|
373
|
+
// eslint-disable-next-line import-x/no-deprecated -- Required to implement the deprecated typeNameSymbol API.
|
|
374
374
|
public get [typeNameSymbol](): TName {
|
|
375
375
|
return identifier;
|
|
376
376
|
}
|
package/src/text/README.md
CHANGED
|
@@ -9,7 +9,7 @@ import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
|
9
9
|
* Returns the number of Unicode code points in `value`.
|
|
10
10
|
* @remarks
|
|
11
11
|
* Use this to translate a JavaScript string length (which is in UTF-16 code units) into
|
|
12
|
-
* the atom/code-point space used by {@link
|
|
12
|
+
* the atom/code-point space used by {@link PlainText} and {@link FormattedText}.
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* ```typescript
|
|
@@ -33,7 +33,7 @@ export function codePointCount(value: string): number {
|
|
|
33
33
|
* Returns the number of UTF-16 code units occupied by the first `count` Unicode code points in `value`,
|
|
34
34
|
* starting at UTF-16 index `start`.
|
|
35
35
|
* @remarks
|
|
36
|
-
* Use this to translate {@link
|
|
36
|
+
* Use this to translate {@link PlainText}-space counts (code points) into JavaScript string indices (UTF-16).
|
|
37
37
|
* One code point outside the Basic Multilingual Plane (e.g. most emoji) occupies two UTF-16 code units.
|
|
38
38
|
*
|
|
39
39
|
* Validates that the requested `count` code points are fully consumable from `start`; silent truncation
|
package/src/text/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
6
|
+
export { PlainText } from "./textDomain.js";
|
|
7
|
+
export { FormattedText } from "./textDomainFormatted.js";
|
|
8
|
+
export { FormattedTextDefault } from "./textDomainFormattedDefault.js";
|
|
9
9
|
export { codePointCount, utf16LengthForCodePoints } from "./codePointUtils.js";
|
package/src/text/textDomain.ts
CHANGED
|
@@ -63,7 +63,7 @@ class TextNode
|
|
|
63
63
|
extends sf.object("Text", {
|
|
64
64
|
content: SchemaFactory.required([() => StringArray], { key: EmptyKey }),
|
|
65
65
|
})
|
|
66
|
-
implements
|
|
66
|
+
implements PlainText.Members, IExposedMethods
|
|
67
67
|
{
|
|
68
68
|
public static [exposeMethodsSymbol](methods: ExposedMethods): void {
|
|
69
69
|
methods.exposeMethod(
|
|
@@ -174,7 +174,7 @@ class TextNode
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
public onCharactersChanged(
|
|
177
|
-
callback: (ops: readonly
|
|
177
|
+
callback: (ops: readonly PlainText.TextOp[] | undefined) => void,
|
|
178
178
|
): () => void {
|
|
179
179
|
return TreeAlpha.on(this.content, "nodeChanged", ({ delta }) =>
|
|
180
180
|
processCharactersChangedDelta(delta, (i) => this.content[i], callback),
|
|
@@ -224,7 +224,7 @@ class StringArray extends sf.array("StringArray", SchemaFactory.string) {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/**
|
|
227
|
-
* Processes an array-node delta into a {@link
|
|
227
|
+
* Processes an array-node delta into a {@link PlainText.TextOp}[] and calls `callback`.
|
|
228
228
|
* @remarks
|
|
229
229
|
* Shared by both the plain `onCharactersChanged` (from `nodeChanged`) and formatted `onContentChanged`
|
|
230
230
|
* (from `treeChanged`) implementations.
|
|
@@ -240,14 +240,14 @@ class StringArray extends sf.array("StringArray", SchemaFactory.string) {
|
|
|
240
240
|
export function processCharactersChangedDelta(
|
|
241
241
|
delta: readonly (ArrayNodeDeltaOp | ArrayNodeTreeChangedDeltaOp)[] | undefined,
|
|
242
242
|
getCharacter: (index: number) => string | undefined,
|
|
243
|
-
callback: (ops: readonly
|
|
243
|
+
callback: (ops: readonly PlainText.TextOp[] | undefined) => void,
|
|
244
244
|
): void {
|
|
245
245
|
if (delta === undefined) {
|
|
246
246
|
callback(undefined);
|
|
247
247
|
return;
|
|
248
248
|
}
|
|
249
249
|
let readPosition = 0;
|
|
250
|
-
const ops:
|
|
250
|
+
const ops: PlainText.TextOp[] = [];
|
|
251
251
|
for (const op of delta) {
|
|
252
252
|
if (op.type === "retain") {
|
|
253
253
|
// `subtreeChanged` is only present on retain ops from `treeChanged` deltas.
|
|
@@ -342,7 +342,7 @@ export function processCharactersChangedDelta(
|
|
|
342
342
|
* in addition to implementing them for text.
|
|
343
343
|
* @alpha
|
|
344
344
|
*/
|
|
345
|
-
export namespace
|
|
345
|
+
export namespace PlainText {
|
|
346
346
|
/**
|
|
347
347
|
* A retain op in a character-level delta — a span of unchanged characters that the consumer should skip over.
|
|
348
348
|
* @sealed
|
|
@@ -360,8 +360,8 @@ export namespace TextAsTree {
|
|
|
360
360
|
/**
|
|
361
361
|
* Whether at least one character in the retained range had a deep change.
|
|
362
362
|
* @remarks
|
|
363
|
-
* Present only on retain ops delivered by {@link @fluidframework/tree#
|
|
364
|
-
* always absent on retain ops delivered by {@link
|
|
363
|
+
* Present only on retain ops delivered by {@link @fluidframework/tree#FormattedText.Members.onContentChanged};
|
|
364
|
+
* always absent on retain ops delivered by {@link PlainText.Members.onCharactersChanged}.
|
|
365
365
|
* When present, `true` indicates the retained range contained a formatting property update
|
|
366
366
|
* or an atom content edit; `false` indicates no deep change.
|
|
367
367
|
*/
|
|
@@ -414,7 +414,7 @@ export namespace TextAsTree {
|
|
|
414
414
|
*/
|
|
415
415
|
export interface Statics {
|
|
416
416
|
/**
|
|
417
|
-
* Construct a {@link
|
|
417
|
+
* Construct a {@link PlainText.(Tree:type)} from a string, where each character (as defined by iterating over the string) becomes a single character in the text node.
|
|
418
418
|
* This combines pairs of utf-16 surrogate code units into single characters as appropriate.
|
|
419
419
|
*/
|
|
420
420
|
fromString(value: string): Tree;
|
|
@@ -433,8 +433,8 @@ export namespace TextAsTree {
|
|
|
433
433
|
* (which often operates on something in between unicode code points and grapheme clusters)
|
|
434
434
|
* and navigation/selection (which typically uses grapheme clusters).
|
|
435
435
|
*
|
|
436
|
-
* @see {@link
|
|
437
|
-
* @see {@link
|
|
436
|
+
* @see {@link PlainText.Statics.fromString} for construction.
|
|
437
|
+
* @see {@link PlainText.(Tree:type)} for schema.
|
|
438
438
|
* @sealed
|
|
439
439
|
* @alpha
|
|
440
440
|
*/
|
|
@@ -447,15 +447,15 @@ export namespace TextAsTree {
|
|
|
447
447
|
characters(): Iterable<string>;
|
|
448
448
|
|
|
449
449
|
/**
|
|
450
|
-
* Optimized way to get a copy of the {@link
|
|
450
|
+
* Optimized way to get a copy of the {@link PlainText.Members.characters} in an array.
|
|
451
451
|
*/
|
|
452
452
|
charactersCopy(): string[];
|
|
453
453
|
|
|
454
454
|
/**
|
|
455
455
|
* Gets the number of characters currently in the text.
|
|
456
456
|
* @remarks
|
|
457
|
-
* The length of {@link
|
|
458
|
-
* This is not the length of the string returned by {@link
|
|
457
|
+
* The length of {@link PlainText.Members.characters}.
|
|
458
|
+
* This is not the length of the string returned by {@link PlainText.Members.fullString},
|
|
459
459
|
* as that string may contain characters which are made up of multiple UTF-16 code units.
|
|
460
460
|
*/
|
|
461
461
|
characterCount(): number;
|
|
@@ -469,7 +469,7 @@ export namespace TextAsTree {
|
|
|
469
469
|
* Insert a range of characters into the string based on character index.
|
|
470
470
|
* @remarks
|
|
471
471
|
* See {@link (TreeArrayNode:interface).insertAt} for more details on the behavior.
|
|
472
|
-
* See {@link
|
|
472
|
+
* See {@link PlainText.Statics.fromString} for how the `additionalCharacters` string is broken into characters.
|
|
473
473
|
* @privateRemarks
|
|
474
474
|
* If we provide ways to customize character boundaries, that could be handled here by taking in an Iterable<string> instead of a string.
|
|
475
475
|
* Doing this currently would enable insertion of text with different character boundaries than the existing text,
|
|
@@ -488,13 +488,13 @@ export namespace TextAsTree {
|
|
|
488
488
|
|
|
489
489
|
/**
|
|
490
490
|
* Subscribe to shallow character-level changes on this text node — inserts and removes only.
|
|
491
|
-
* @param callback - Called after each change with a sequence of {@link
|
|
491
|
+
* @param callback - Called after each change with a sequence of {@link PlainText.TextOp}s describing what changed,
|
|
492
492
|
* or `undefined` when a delta could not be computed (e.g. during a schema upgrade).
|
|
493
493
|
* @returns A cleanup function that unsubscribes the callback when called.
|
|
494
494
|
* @remarks
|
|
495
495
|
* Only fires on shallow changes — inserts and removes.
|
|
496
496
|
* It does not fire on deep changes such as formatting property updates on existing characters.
|
|
497
|
-
* For formatted text, use {@link @fluidframework/tree#
|
|
497
|
+
* For formatted text, use {@link @fluidframework/tree#FormattedText.Members.onContentChanged} to also receive deep changes.
|
|
498
498
|
*
|
|
499
499
|
* All counts in the delivered ops are in Unicode code points, not UTF-16 code units.
|
|
500
500
|
* For characters outside the Basic Multilingual Plane (e.g. emoji), one code point
|
|
@@ -504,17 +504,17 @@ export namespace TextAsTree {
|
|
|
504
504
|
}
|
|
505
505
|
|
|
506
506
|
/**
|
|
507
|
-
* Schema for a {@link
|
|
507
|
+
* Schema for a {@link PlainText.(Tree:variable)} node.
|
|
508
508
|
* @remarks
|
|
509
|
-
* See {@link
|
|
509
|
+
* See {@link PlainText.Statics} for static APIs on this schema, including construction.
|
|
510
510
|
* @alpha
|
|
511
511
|
*/
|
|
512
512
|
export const Tree = eraseSchemaDetails<Members, Statics>()(TextNode);
|
|
513
513
|
|
|
514
514
|
/**
|
|
515
|
-
* Node for the {@link
|
|
515
|
+
* Node for the {@link PlainText.(Tree:type)} schema exposing the {@link PlainText.Members} API.
|
|
516
516
|
* @remarks
|
|
517
|
-
* Create using {@link
|
|
517
|
+
* Create using {@link PlainText.Statics.fromString}.
|
|
518
518
|
* @alpha
|
|
519
519
|
*/
|
|
520
520
|
export type Tree = Members & TreeNode & WithType<"com.fluidframework.text.Text">;
|