@grahlnn/comps 0.1.5 → 0.1.7

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/dist/index.js CHANGED
@@ -3077,6 +3077,12 @@ function readRootOrigin(node) {
3077
3077
  const rect = node.getBoundingClientRect();
3078
3078
  return { left: rect.left, top: rect.top };
3079
3079
  }
3080
+ function readFlowInlineSize(node) {
3081
+ if (node === null) {
3082
+ return null;
3083
+ }
3084
+ return node.getBoundingClientRect().width;
3085
+ }
3080
3086
  function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize) {
3081
3087
  const backend = getPretextMorphMeasurementBackend(text, layoutContext);
3082
3088
  if (backend !== "probe") {
@@ -3099,6 +3105,12 @@ function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, us
3099
3105
  }
3100
3106
  return "dom";
3101
3107
  }
3108
+ function resolveContentWidthLockInlineSize(layoutHint) {
3109
+ if (layoutHint.flowInlineSize !== null) {
3110
+ return layoutHint.flowInlineSize;
3111
+ }
3112
+ return layoutHint.snapshot.width;
3113
+ }
3102
3114
  function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
3103
3115
  if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
3104
3116
  return true;
@@ -3109,7 +3121,7 @@ function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
3109
3121
  if (layoutHint === null || !isSingleLineSnapshot(layoutHint.snapshot)) {
3110
3122
  return false;
3111
3123
  }
3112
- return nearlyEqual(layoutHint.layoutInlineSize, layoutHint.snapshot.width, MORPH.contentWidthLockEpsilon);
3124
+ return nearlyEqual(layoutHint.layoutInlineSize, resolveContentWidthLockInlineSize(layoutHint), MORPH.contentWidthLockEpsilon);
3113
3125
  }
3114
3126
  function createMorphMeasurementRequest({
3115
3127
  text,
@@ -3244,6 +3256,7 @@ function measureFromNodes({
3244
3256
  snapshot,
3245
3257
  layoutInlineSize,
3246
3258
  reservedInlineSize,
3259
+ flowInlineSize: null,
3247
3260
  rootOrigin: readRootOrigin(root)
3248
3261
  };
3249
3262
  }
@@ -3255,6 +3268,7 @@ function pinMeasurementToCurrentOrigin(measurement, origin) {
3255
3268
  snapshot: measurement.snapshot,
3256
3269
  layoutInlineSize: measurement.layoutInlineSize,
3257
3270
  reservedInlineSize: measurement.reservedInlineSize,
3271
+ flowInlineSize: measurement.flowInlineSize,
3258
3272
  rootOrigin: origin
3259
3273
  };
3260
3274
  }
@@ -3384,7 +3398,7 @@ function sameMeasurement(a, b) {
3384
3398
  if (a === b) {
3385
3399
  return true;
3386
3400
  }
3387
- return sameSnapshot(a.snapshot, b.snapshot) && nearlyEqual(a.layoutInlineSize, b.layoutInlineSize) && (a.reservedInlineSize === null && b.reservedInlineSize === null || a.reservedInlineSize !== null && b.reservedInlineSize !== null && nearlyEqual(a.reservedInlineSize, b.reservedInlineSize)) && nearlyEqual(a.rootOrigin.left, b.rootOrigin.left) && nearlyEqual(a.rootOrigin.top, b.rootOrigin.top);
3401
+ return sameSnapshot(a.snapshot, b.snapshot) && nearlyEqual(a.layoutInlineSize, b.layoutInlineSize) && (a.reservedInlineSize === null && b.reservedInlineSize === null || a.reservedInlineSize !== null && b.reservedInlineSize !== null && nearlyEqual(a.reservedInlineSize, b.reservedInlineSize)) && (a.flowInlineSize === null && b.flowInlineSize === null || a.flowInlineSize !== null && b.flowInlineSize !== null && nearlyEqual(a.flowInlineSize, b.flowInlineSize)) && nearlyEqual(a.rootOrigin.left, b.rootOrigin.left) && nearlyEqual(a.rootOrigin.top, b.rootOrigin.top);
3388
3402
  }
3389
3403
  function refreshAnimatingTarget(activeTarget, measurement) {
3390
3404
  if (sameMeasurement(activeTarget, measurement)) {
@@ -3394,6 +3408,7 @@ function refreshAnimatingTarget(activeTarget, measurement) {
3394
3408
  snapshot: activeTarget.snapshot,
3395
3409
  layoutInlineSize: measurement.layoutInlineSize,
3396
3410
  reservedInlineSize: measurement.reservedInlineSize,
3411
+ flowInlineSize: activeTarget.flowInlineSize,
3397
3412
  rootOrigin: measurement.rootOrigin
3398
3413
  };
3399
3414
  }
@@ -3572,6 +3587,7 @@ function reconcileMorphChange({
3572
3587
  }
3573
3588
  function syncCommittedRootOriginWhenIdle({
3574
3589
  root,
3590
+ flowTextRef,
3575
3591
  layoutContext,
3576
3592
  state,
3577
3593
  session
@@ -3583,8 +3599,9 @@ function syncCommittedRootOriginWhenIdle({
3583
3599
  return;
3584
3600
  }
3585
3601
  const nextRootOrigin = readRootOrigin(root);
3602
+ const nextFlowInlineSize = readFlowInlineSize(flowTextRef.current);
3586
3603
  const committedMeasurement = state.measurement;
3587
- if (nearlyEqual(committedMeasurement.rootOrigin.left, nextRootOrigin.left) && nearlyEqual(committedMeasurement.rootOrigin.top, nextRootOrigin.top)) {
3604
+ if (nearlyEqual(committedMeasurement.rootOrigin.left, nextRootOrigin.left) && nearlyEqual(committedMeasurement.rootOrigin.top, nextRootOrigin.top) && (committedMeasurement.flowInlineSize === null && nextFlowInlineSize === null || committedMeasurement.flowInlineSize !== null && nextFlowInlineSize !== null && nearlyEqual(committedMeasurement.flowInlineSize, nextFlowInlineSize))) {
3588
3605
  session.committed = committedMeasurement;
3589
3606
  return;
3590
3607
  }
@@ -3592,6 +3609,7 @@ function syncCommittedRootOriginWhenIdle({
3592
3609
  snapshot: committedMeasurement.snapshot,
3593
3610
  layoutInlineSize: committedMeasurement.layoutInlineSize,
3594
3611
  reservedInlineSize: committedMeasurement.reservedInlineSize,
3612
+ flowInlineSize: nextFlowInlineSize,
3595
3613
  rootOrigin: nextRootOrigin
3596
3614
  };
3597
3615
  }
@@ -3692,18 +3710,6 @@ function getMeasurementLayerStyle(layoutContext, useContentInlineSize = false) {
3692
3710
  function resolveFlowText(committedMeasurement, stateMeasurement, text) {
3693
3711
  return committedMeasurement?.snapshot.text ?? stateMeasurement?.snapshot.text ?? text;
3694
3712
  }
3695
- function resolveVisibleFlowText(pendingBootstrapText, committedMeasurement, stateMeasurement, text) {
3696
- return pendingBootstrapText ?? resolveFlowText(committedMeasurement, stateMeasurement, text);
3697
- }
3698
- function resolveActivationBootstrapText(isActivated, previousText, nextText) {
3699
- if (!isActivated && nextText !== previousText) {
3700
- return previousText;
3701
- }
3702
- return null;
3703
- }
3704
- function shouldDeferTargetMeasurement(committedMeasurement, pendingBootstrapText, text) {
3705
- return committedMeasurement === null && pendingBootstrapText !== null && pendingBootstrapText !== text;
3706
- }
3707
3713
  function getOverlayStyle(plan) {
3708
3714
  return {
3709
3715
  ...OVERLAY_STYLE,
@@ -3791,55 +3797,30 @@ function MeasurementLayer({
3791
3797
  }, segment.key, false, undefined, this))
3792
3798
  }, undefined, false, undefined, this);
3793
3799
  }
3794
- function useMorphTransition(text, className, bootstrapText = null) {
3800
+ function useMorphTransition(text, className) {
3795
3801
  const { ref, layoutContext } = useObservedLayoutContext([className]);
3802
+ const flowTextRef = useRef(null);
3796
3803
  const measurementLayerRef = useRef(null);
3797
- const bootstrapMeasurementLayerRef = useRef(null);
3798
3804
  const completedDomMeasurementKeyRef = useRef(null);
3799
3805
  const domMeasurementSnapshotCacheRef = useRef(new Map);
3800
- const pendingBootstrapTextRef = useRef(bootstrapText);
3801
3806
  const sessionRef = useRef({ ...EMPTY_SESSION });
3802
3807
  const timelineRef = useRef({ ...EMPTY_TIMELINE });
3803
3808
  const [domMeasurementRequestKey, setDomMeasurementRequestKey] = useState(null);
3804
3809
  const [state, setState] = useState(EMPTY_STATE);
3805
- if (pendingBootstrapTextRef.current === null && bootstrapText !== null && bootstrapText !== text && sessionRef.current.committed === null) {
3806
- pendingBootstrapTextRef.current = bootstrapText;
3807
- }
3808
3810
  let measurementHint = sessionRef.current.committed;
3809
3811
  if (sessionRef.current.animating) {
3810
3812
  measurementHint = sessionRef.current.target ?? sessionRef.current.committed;
3811
3813
  }
3812
- let pendingBootstrapText = null;
3813
- if (sessionRef.current.committed === null) {
3814
- pendingBootstrapText = pendingBootstrapTextRef.current;
3815
- }
3816
- const isBootstrapping = shouldDeferTargetMeasurement(sessionRef.current.committed, pendingBootstrapText, text);
3817
- const measurementRequest = useMemo(() => {
3818
- if (isBootstrapping) {
3819
- return null;
3820
- }
3821
- return createMorphMeasurementRequest({
3822
- text,
3823
- layoutContext,
3824
- layoutHint: measurementHint
3825
- });
3826
- }, [text, layoutContext, measurementHint, isBootstrapping]);
3827
- const bootstrapMeasurementRequest = useMemo(() => {
3828
- if (!isBootstrapping || pendingBootstrapText === null) {
3829
- return null;
3830
- }
3831
- return createMorphMeasurementRequest({
3832
- text: pendingBootstrapText,
3833
- layoutContext,
3834
- layoutHint: null
3835
- });
3836
- }, [pendingBootstrapText, layoutContext, isBootstrapping]);
3814
+ const measurementRequest = useMemo(() => createMorphMeasurementRequest({
3815
+ text,
3816
+ layoutContext,
3817
+ layoutHint: measurementHint
3818
+ }), [text, layoutContext, measurementHint]);
3837
3819
  const renderText = measurementRequest?.renderText ?? text;
3838
3820
  const useContentInlineSize = measurementRequest?.useContentInlineSize ?? false;
3839
3821
  const measurementBackend = measurementRequest?.measurementBackend ?? null;
3840
3822
  const segments = measurementRequest?.segments ?? EMPTY_SEGMENTS;
3841
3823
  const domMeasurementKey = measurementRequest?.domMeasurementKey ?? null;
3842
- const shouldRenderBootstrapSourceMeasurementLayer = bootstrapMeasurementRequest?.domMeasurementKey !== null;
3843
3824
  useLayoutEffect(() => {
3844
3825
  if (ref.current === null || layoutContext === null) {
3845
3826
  completedDomMeasurementKeyRef.current = null;
@@ -3861,36 +3842,6 @@ function useMorphTransition(text, className, bootstrapText = null) {
3861
3842
  });
3862
3843
  return;
3863
3844
  }
3864
- if (isBootstrapping && bootstrapMeasurementRequest !== null) {
3865
- let bootstrapDomSnapshot = null;
3866
- if (bootstrapMeasurementRequest.domMeasurementKey !== null && canCacheMeasurementLayerSnapshot(bootstrapMeasurementRequest.measurementBackend)) {
3867
- bootstrapDomSnapshot = readCachedMorphSnapshot(domMeasurementSnapshotCacheRef.current, bootstrapMeasurementRequest.domMeasurementKey);
3868
- }
3869
- if (bootstrapMeasurementRequest.domMeasurementKey !== null && bootstrapDomSnapshot === null && bootstrapMeasurementLayerRef.current === null) {
3870
- return;
3871
- }
3872
- const bootstrapMeasurement = measureFromNodes({
3873
- root: ref.current,
3874
- layoutContext,
3875
- layoutHint: null,
3876
- layer: bootstrapMeasurementLayerRef.current,
3877
- measurementBackend: bootstrapMeasurementRequest.measurementBackend,
3878
- snapshotOverride: bootstrapDomSnapshot,
3879
- text: bootstrapMeasurementRequest.text,
3880
- renderText: bootstrapMeasurementRequest.renderText,
3881
- segments: bootstrapMeasurementRequest.segments
3882
- });
3883
- if (bootstrapMeasurementRequest.domMeasurementKey !== null && bootstrapDomSnapshot === null && canCacheMeasurementLayerSnapshot(bootstrapMeasurementRequest.measurementBackend)) {
3884
- rememberCachedMorphSnapshot(domMeasurementSnapshotCacheRef.current, bootstrapMeasurementRequest.domMeasurementKey, bootstrapMeasurement.snapshot);
3885
- }
3886
- completedDomMeasurementKeyRef.current = null;
3887
- pendingBootstrapTextRef.current = null;
3888
- if (domMeasurementRequestKey !== null) {
3889
- setDomMeasurementRequestKey(null);
3890
- }
3891
- commitStaticMeasurement(sessionRef.current, bootstrapMeasurement, setState);
3892
- return;
3893
- }
3894
3845
  if (domMeasurementKey !== null) {
3895
3846
  let cachedSnapshot = null;
3896
3847
  if (canCacheMeasurementLayerSnapshot(measurementBackend)) {
@@ -3977,15 +3928,13 @@ function useMorphTransition(text, className, bootstrapText = null) {
3977
3928
  layoutContext,
3978
3929
  measurementBackend,
3979
3930
  measurementRequest,
3980
- isBootstrapping,
3981
- pendingBootstrapText,
3982
- bootstrapMeasurementRequest,
3983
3931
  domMeasurementKey,
3984
3932
  domMeasurementRequestKey
3985
3933
  ]);
3986
3934
  useLayoutEffect(() => {
3987
3935
  syncCommittedRootOriginWhenIdle({
3988
3936
  root: ref.current,
3937
+ flowTextRef,
3989
3938
  layoutContext,
3990
3939
  state,
3991
3940
  session: sessionRef.current
@@ -3999,71 +3948,36 @@ function useMorphTransition(text, className, bootstrapText = null) {
3999
3948
  return {
4000
3949
  committedMeasurement: sessionRef.current.committed,
4001
3950
  domMeasurementRequestKey,
3951
+ flowTextRef,
4002
3952
  ref,
4003
- bootstrapMeasurementLayerRef,
4004
- measurementBackend,
4005
3953
  measurementLayerRef,
4006
3954
  renderText,
4007
3955
  segments,
4008
3956
  layoutContext,
4009
3957
  state,
4010
- pendingBootstrapText,
4011
- shouldRenderBootstrapSourceMeasurementLayer,
4012
- bootstrapMeasurementRequest,
4013
3958
  useContentInlineSize
4014
3959
  };
4015
3960
  }
4016
- function StaticTorph({ text, className }) {
4017
- return /* @__PURE__ */ jsxDEV("div", {
4018
- className,
4019
- children: [
4020
- /* @__PURE__ */ jsxDEV("span", {
4021
- style: SCREEN_READER_ONLY_STYLE,
4022
- children: text
4023
- }, undefined, false, undefined, this),
4024
- /* @__PURE__ */ jsxDEV("span", {
4025
- "aria-hidden": "true",
4026
- style: FALLBACK_TEXT_STYLE,
4027
- children: text
4028
- }, undefined, false, undefined, this)
4029
- ]
4030
- }, undefined, true, undefined, this);
4031
- }
4032
3961
  function ActiveTorph({
4033
3962
  text,
4034
- className,
4035
- bootstrapText
3963
+ className
4036
3964
  }) {
4037
3965
  const {
4038
3966
  committedMeasurement,
4039
3967
  domMeasurementRequestKey,
3968
+ flowTextRef,
4040
3969
  ref,
4041
- bootstrapMeasurementLayerRef,
4042
- measurementBackend,
4043
3970
  measurementLayerRef,
4044
3971
  renderText,
4045
3972
  segments,
4046
3973
  layoutContext,
4047
3974
  state,
4048
- pendingBootstrapText,
4049
- shouldRenderBootstrapSourceMeasurementLayer,
4050
- bootstrapMeasurementRequest,
4051
3975
  useContentInlineSize
4052
- } = useMorphTransition(text, className, bootstrapText);
3976
+ } = useMorphTransition(text, className);
4053
3977
  const plan = state.plan;
4054
3978
  const shouldRenderOverlay = state.stage !== "idle" && plan !== null;
4055
3979
  const shouldRenderMeasurementLayer = domMeasurementRequestKey !== null;
4056
- const flowText = resolveVisibleFlowText(pendingBootstrapText, committedMeasurement, state.measurement, text);
4057
- let bootstrapMeasurementLayer = null;
4058
- if (shouldRenderBootstrapSourceMeasurementLayer && bootstrapMeasurementRequest !== null) {
4059
- bootstrapMeasurementLayer = /* @__PURE__ */ jsxDEV(MeasurementLayer, {
4060
- layerRef: bootstrapMeasurementLayerRef,
4061
- layoutContext,
4062
- text: bootstrapMeasurementRequest.renderText,
4063
- segments: bootstrapMeasurementRequest.segments,
4064
- useContentInlineSize: bootstrapMeasurementRequest.useContentInlineSize
4065
- }, undefined, false, undefined, this);
4066
- }
3980
+ const flowText = resolveFlowText(committedMeasurement, state.measurement, text);
4067
3981
  let measurementLayer = null;
4068
3982
  if (shouldRenderMeasurementLayer) {
4069
3983
  measurementLayer = /* @__PURE__ */ jsxDEV(MeasurementLayer, {
@@ -4093,9 +4007,11 @@ function ActiveTorph({
4093
4007
  /* @__PURE__ */ jsxDEV("span", {
4094
4008
  "aria-hidden": "true",
4095
4009
  style: getFallbackTextStyle(shouldRenderOverlay),
4096
- children: flowText
4010
+ children: /* @__PURE__ */ jsxDEV("span", {
4011
+ ref: flowTextRef,
4012
+ children: flowText
4013
+ }, undefined, false, undefined, this)
4097
4014
  }, undefined, false, undefined, this),
4098
- bootstrapMeasurementLayer,
4099
4015
  measurementLayer,
4100
4016
  overlay
4101
4017
  ]
@@ -4105,37 +4021,16 @@ function Torph({
4105
4021
  text,
4106
4022
  className
4107
4023
  }) {
4108
- const [isActivated, setIsActivated] = useState(false);
4109
- const previousTextRef = useRef(text);
4110
- const bootstrapText = resolveActivationBootstrapText(isActivated, previousTextRef.current, text);
4111
- const shouldActivate = isActivated || bootstrapText !== null;
4112
- useLayoutEffect(() => {
4113
- if (!isActivated && text !== previousTextRef.current) {
4114
- previousTextRef.current = text;
4115
- setIsActivated(true);
4116
- return;
4117
- }
4118
- previousTextRef.current = text;
4119
- }, [isActivated, text]);
4120
- if (shouldActivate) {
4121
- return /* @__PURE__ */ jsxDEV(ActiveTorph, {
4122
- text,
4123
- className,
4124
- bootstrapText
4125
- }, undefined, false, undefined, this);
4126
- }
4127
- return /* @__PURE__ */ jsxDEV(StaticTorph, {
4024
+ return /* @__PURE__ */ jsxDEV(ActiveTorph, {
4128
4025
  text,
4129
4026
  className
4130
4027
  }, undefined, false, undefined, this);
4131
4028
  }
4132
4029
  export {
4133
4030
  supportsIntrinsicWidthLock,
4134
- shouldDeferTargetMeasurement,
4135
- resolveVisibleFlowText,
4136
4031
  resolveMorphFrameBounds,
4137
4032
  resolveFlowText,
4138
- resolveActivationBootstrapText,
4033
+ resolveContentWidthLockInlineSize,
4139
4034
  pairMorphCharacters,
4140
4035
  needsMeasurementLayer,
4141
4036
  measureMorphSnapshotFromLayer,
@@ -20,6 +20,7 @@ export type MorphMeasurement = {
20
20
  snapshot: MorphSnapshot;
21
21
  layoutInlineSize: number;
22
22
  reservedInlineSize: number | null;
23
+ flowInlineSize: number | null;
23
24
  rootOrigin: {
24
25
  left: number;
25
26
  top: number;
@@ -79,6 +80,7 @@ type GlyphExit = {
79
80
  type GlyphPairing = GlyphMove | GlyphEnter | GlyphExit;
80
81
  export declare function needsMeasurementLayer(measurementBackend: PretextMorphMeasurementBackend, renderText: string): boolean;
81
82
  export declare function measureMorphSnapshotFromLayer(text: string, renderText: string, segments: readonly MorphSegment[], layer: HTMLElement | null): MorphSnapshot;
83
+ export declare function resolveContentWidthLockInlineSize(layoutHint: MorphMeasurement): number;
82
84
  export declare function pairMorphCharacters(previous: MorphCharacterLayout[], next: MorphCharacterLayout[]): GlyphPairing[];
83
85
  export declare function resolveMorphFrameBounds(previous: MorphSnapshot, next: MorphSnapshot): {
84
86
  width: number;
@@ -95,9 +97,6 @@ export declare function getRootDisplay(layoutContext: LayoutContext | null): "gr
95
97
  export declare function getRootStyle(stage: MorphStage, plan: MorphRenderPlan | null, measurement: MorphMeasurement | null, layoutContext: LayoutContext | null): CSSProperties;
96
98
  export declare function getMeasurementLayerStyle(layoutContext: LayoutContext | null, useContentInlineSize?: boolean): CSSProperties;
97
99
  export declare function resolveFlowText(committedMeasurement: MorphMeasurement | null, stateMeasurement: MorphMeasurement | null, text: string): string;
98
- export declare function resolveVisibleFlowText(pendingBootstrapText: string | null, committedMeasurement: MorphMeasurement | null, stateMeasurement: MorphMeasurement | null, text: string): string;
99
- export declare function resolveActivationBootstrapText(isActivated: boolean, previousText: string, nextText: string): string | null;
100
- export declare function shouldDeferTargetMeasurement(committedMeasurement: MorphMeasurement | null, pendingBootstrapText: string | null, text: string): boolean;
101
100
  export declare function Torph({ text, className, }: {
102
101
  text: string;
103
102
  className?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grahlnn/comps",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "React components from grahlnn/comps.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",