Skip to content

Commit

Permalink
fix: properly manage states
Browse files Browse the repository at this point in the history
  • Loading branch information
zobweyt committed Nov 19, 2024
1 parent 08496c2 commit 31df2d7
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "solid-js";

export interface SegmentedControlContextValue {
value: Accessor<string | undefined>;
defaultValue: Accessor<string | undefined>;
orientation: Accessor<Orientation | undefined>;
root: Accessor<HTMLElement | undefined>;
Expand Down
23 changes: 13 additions & 10 deletions packages/core/src/segmented-control/segmented-control-indicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,18 @@ export function SegmentedControlIndicator<T extends ValidComponent = "div">(
const [resizing, setResizing] = createSignal(false);

const computeStyle = () => {
const el = context.selectedItem();
if (!el) return;
const element = context.selectedItem();

if (!element) {
// TODO: Listen for transition to end here before removing the style.
setStyle(undefined);
return;
}

setStyle({
width: `${el.offsetWidth}px`,
height: `${el.offsetHeight}px`,
transform: computeTransform(el),
width: `${element.offsetWidth}px`,
height: `${element.offsetHeight}px`,
transform: computeTransform(element),
"transition-duration": resizing() ? "0ms" : undefined,
});
};
Expand All @@ -59,12 +64,10 @@ export function SegmentedControlIndicator<T extends ValidComponent = "div">(
};

createEffect(
on(context.selectedItem, () => {
// This effect should only run if the style is set; otherwise, the style will be computed
// in the resize observer callback, which will prevent the initial transition while resizing.
if (!style()) return;

on(context.value, () => {
setResizing(!style());
computeStyle();
setResizing(false);
}),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ import { mergeRefs } from "@kobalte/utils";
import {
type Component,
type ValidComponent,
createEffect,
createSignal,
onCleanup,
splitProps,
} from "solid-js";

import type { ElementOf, PolymorphicProps } from "../polymorphic";
import { createFormResetListener } from "../primitives";
import {
RadioGroup,
type RadioGroupItemInputCommonProps,
type RadioGroupItemInputOptions,
type RadioGroupItemInputRenderProps,
} from "../radio-group";
import { useRadioGroupItemContext } from "../radio-group/radio-group-item-context";
import { useSegmentedControlContext } from "./segmented-control-context";

export interface SegmentedControlItemInputOptions
extends RadioGroupItemInputOptions {}
Expand All @@ -36,34 +35,16 @@ export const SegmentedControlItemInput = <T extends ValidComponent = "input">(
props: PolymorphicProps<T, SegmentedControlItemInputProps<T>>,
) => {
const radioGroupItemContext = useRadioGroupItemContext();
const segmentedControlContext = useSegmentedControlContext();

const [localProps, otherProps] = splitProps(props, ["ref"]);

const [ref, setRef] = createSignal<HTMLInputElement>();

createEffect(() => {
const element = ref();
if (!element) return;

const form = element.form;
if (!form) return;

const handleReset = (_e: Event) => {
requestAnimationFrame(() => {
if (
radioGroupItemContext.value() ===
segmentedControlContext.defaultValue()
) {
radioGroupItemContext.select();
}
});
};

form.addEventListener("reset", handleReset);

onCleanup(() => {
form.removeEventListener("reset", handleReset);
createFormResetListener(ref, () => {
requestAnimationFrame(() => {
if (radioGroupItemContext.isDefault()) {
radioGroupItemContext.select();
}
});
});

Expand Down
19 changes: 9 additions & 10 deletions packages/core/src/segmented-control/segmented-control-root.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mergeRefs } from "@kobalte/utils";
import {
type ValidComponent,
createEffect,
createSignal,
mergeProps,
splitProps,
Expand All @@ -17,18 +18,9 @@ export type SegmentedControlRootProps = RadioGroupRootProps;
export const SegmentedControlRoot = <T extends ValidComponent = "div">(
props: PolymorphicProps<T, SegmentedControlRootProps>,
) => {
if (!props.value && !props.defaultValue) {
throw new Error(
"[kobalte]: No value or default value provided for the segmented control.",
);
}

if (!props.defaultValue) {
props.defaultValue = props.value;
}

const mergedProps = mergeProps(
{
defaultValue: props.value,
orientation: "horizontal",
},
props,
Expand All @@ -40,13 +32,20 @@ export const SegmentedControlRoot = <T extends ValidComponent = "div">(
const [selectedItem, setSelectedItem] = createSignal<HTMLElement>();

const context: SegmentedControlContextValue = {
value: () => otherProps.value,
defaultValue: () => otherProps.defaultValue,
orientation: () => otherProps.orientation,
root: ref,
selectedItem: selectedItem,
setSelectedItem: setSelectedItem,
};

createEffect(() => {
if (context.value()) return;

setSelectedItem(undefined);
});

return (
<SegmentedControlContext.Provider value={context}>
<RadioGroup ref={mergeRefs(setRef, localProps.ref)} {...otherProps} />
Expand Down

0 comments on commit 31df2d7

Please sign in to comment.