Skip to content

Commit d64f886

Browse files
committed
fix: Bug fixes on ssr.
1 parent 7852ff7 commit d64f886

File tree

1 file changed

+76
-35
lines changed

1 file changed

+76
-35
lines changed

src/index.tsx

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,65 @@ import {
44
SlottedTag,
55
slottedStyles,
66
partitionParts,
7-
type PartitionedParts,
87
NumberFlowLite,
98
prefersReducedMotion,
109
canAnimate as _canAnimate,
11-
} from 'number-flow'
12-
import { JSX } from 'solid-js/jsx-runtime'
13-
import { createMemo, onMount, splitProps } from 'solid-js'
14-
import { Dynamic } from 'solid-js/web'
15-
export type { Value, Format, Trend } from 'number-flow'
10+
} from 'number-flow';
11+
import { JSX } from 'solid-js/jsx-runtime';
12+
import { createEffect, createMemo, createSignal, onMount, splitProps } from 'solid-js';
13+
import { Dynamic } from 'solid-js/web';
14+
export type { Value, Format, Trend } from 'number-flow';
1615

1716
// Can't wait to not have to do this in React 19:
18-
const OBSERVED_ATTRIBUTES = ['parts'] as const
19-
type ObservedAttribute = (typeof OBSERVED_ATTRIBUTES)[number]
17+
const OBSERVED_ATTRIBUTES = ['parts'] as const;
18+
type ObservedAttribute = (typeof OBSERVED_ATTRIBUTES)[number];
2019
export class NumberFlowElement extends NumberFlowLite {
21-
static observedAttributes = OBSERVED_ATTRIBUTES
20+
static observedAttributes = OBSERVED_ATTRIBUTES;
2221
attributeChangedCallback(attr: ObservedAttribute, _oldValue: string, newValue: string) {
23-
this[attr] = JSON.parse(newValue)
22+
this[attr] = JSON.parse(newValue);
2423
}
2524
}
2625

2726
export type NumberFlowProps = JSX.HTMLAttributes<NumberFlowElement> & {
28-
value: Value
29-
locales?: Intl.LocalesArgument
30-
format?: Format
31-
isolate?: boolean
32-
animated?: boolean
33-
respectMotionPreference?: boolean
34-
willChange?: boolean
27+
value: Value;
28+
locales?: Intl.LocalesArgument;
29+
format?: Format;
30+
isolate?: boolean;
31+
animated?: boolean;
32+
respectMotionPreference?: boolean;
33+
willChange?: boolean;
3534
// animateDependencies?: React.DependencyList
36-
onAnimationsStart?: () => void
37-
onAnimationsFinish?: () => void
38-
trend?: (typeof NumberFlowElement)['prototype']['trend']
39-
opacityTiming?: (typeof NumberFlowElement)['prototype']['opacityTiming']
40-
transformTiming?: (typeof NumberFlowElement)['prototype']['transformTiming']
41-
spinTiming?: (typeof NumberFlowElement)['prototype']['spinTiming']
42-
}
35+
onAnimationsStart?: () => void;
36+
onAnimationsFinish?: () => void;
37+
trend?: (typeof NumberFlowElement)['prototype']['trend'];
38+
opacityTiming?: (typeof NumberFlowElement)['prototype']['opacityTiming'];
39+
transformTiming?: (typeof NumberFlowElement)['prototype']['transformTiming'];
40+
spinTiming?: (typeof NumberFlowElement)['prototype']['spinTiming'];
41+
};
4342

4443
// You're supposed to cache these between uses:
4544
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
4645
// Serialize to strings b/c React:
47-
const formatters: Record<string, Intl.NumberFormat> = {}
46+
const formatters: Record<string, Intl.NumberFormat> = {};
4847

4948
export default function NumberFlow(props: NumberFlowProps) {
5049
onMount(() => {
51-
NumberFlowElement.define()
52-
})
50+
NumberFlowElement.define();
51+
});
5352

5453
const localesString = createMemo(
5554
() => (props.locales ? JSON.stringify(props.locales) : ''),
5655
[props.locales],
57-
)
58-
const formatString = createMemo(() => (props.format ? JSON.stringify(props.format) : ''))
56+
);
57+
const formatString = createMemo(() => (props.format ? JSON.stringify(props.format) : ''));
5958
const parts = createMemo(() => {
6059
const formatter = (formatters[`${localesString}:${formatString}`] ??= new Intl.NumberFormat(
6160
props.locales,
6261
props.format,
63-
))
62+
));
6463

65-
return partitionParts(props.value, formatter)
66-
})
64+
return partitionParts(props.value, formatter);
65+
});
6766

6867
const [_used, others] = splitProps(props, [
6968
// For Root
@@ -80,13 +79,24 @@ export default function NumberFlow(props: NumberFlowProps) {
8079
'opacityTiming',
8180
'transformTiming',
8281
'spinTiming',
83-
])
82+
]);
83+
84+
onMount(() => {
85+
// This is a workaround until this gets fixed: https://github.com/solidjs/solid/issues/2339
86+
const el = props.ref as unknown as HTMLElement;
87+
const _parts = el.getAttribute('attr:parts');
88+
if (_parts) {
89+
el.removeAttribute('attr:parts');
90+
el.setAttribute('parts', _parts);
91+
}
92+
});
8493

8594
return (
8695
<Dynamic
96+
ref={props.ref}
8797
component={'number-flow'}
88-
// https://docs.solidjs.com/reference/jsx-attributes/attr
8998
class={props.class}
99+
// https://docs.solidjs.com/reference/jsx-attributes/attr
90100
attr:data-will-change={props.willChange ? '' : undefined}
91101
{...others}
92102
attr:parts={JSON.stringify(parts())}
@@ -95,5 +105,36 @@ export default function NumberFlow(props: NumberFlowProps) {
95105
{parts().formatted}
96106
</Dynamic>
97107
</Dynamic>
98-
)
108+
);
109+
}
110+
111+
// SSR-safe canAnimate
112+
/** Unfinished and untested. */
113+
export function useCanAnimate(
114+
props: { respectMotionPreference: boolean } = { respectMotionPreference: true },
115+
) {
116+
const [canAnimate, setCanAnimate] = createSignal(_canAnimate);
117+
const [reducedMotion, setReducedMotion] = createSignal(false);
118+
119+
// Handle SSR:
120+
onMount(() => {
121+
setCanAnimate(_canAnimate);
122+
setReducedMotion(prefersReducedMotion?.matches ?? false);
123+
});
124+
125+
// Listen for reduced motion changes if needed:
126+
createEffect(() => {
127+
if (!props.respectMotionPreference) return;
128+
const onChange = ({ matches }: MediaQueryListEvent) => {
129+
setReducedMotion(matches);
130+
};
131+
prefersReducedMotion?.addEventListener('change', onChange);
132+
return () => {
133+
prefersReducedMotion?.removeEventListener('change', onChange);
134+
};
135+
});
136+
137+
return createMemo<boolean>(() => {
138+
return canAnimate() && (!props.respectMotionPreference || !reducedMotion);
139+
});
99140
}

0 commit comments

Comments
 (0)