Skip to content

Commit

Permalink
Added some more tests and fixed props for checkbox group item
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubhdeep12 committed Oct 18, 2024
1 parent 075b729 commit a0c61ae
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 36 deletions.
19 changes: 14 additions & 5 deletions packages/core/src/checkbox-group/checkbox-group-item-context.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { useContext } from "solid-js";
import { Accessor, createContext, useContext } from "solid-js";
import {
CheckboxContext,
type CheckboxContextValue,
type CheckboxDataSet,
} from "../checkbox/checkbox-context";

export interface CheckboxGroupItemDataSet extends CheckboxDataSet {}
export interface CheckboxGroupItemDataSet extends CheckboxDataSet {
"data-disabled": string | undefined
}

export interface CheckboxGroupItemContextValue extends CheckboxContextValue {}
export interface CheckboxGroupItemContextValue extends CheckboxContextValue {
isDisabled: Accessor<boolean>;
registerInput: (id: string) => () => void;
registerLabel: (id: string) => () => void;
registerDescription: (id: string) => () => void;
inputId: Accessor<string | undefined>;
labelId: Accessor<string | undefined>;
descriptionId: Accessor<string | undefined>;
}

export const CheckboxGroupItemContext = CheckboxContext;
export const CheckboxGroupItemContext = createContext<CheckboxGroupItemContextValue>();;

export function useCheckboxGroupItemContext() {
const context = useContext(CheckboxGroupItemContext);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Component, ValidComponent } from "solid-js";
import { createEffect, onCleanup, type Component, type ValidComponent } from "solid-js";

import type {
CheckboxDescriptionCommonProps,
Expand All @@ -14,6 +14,7 @@ import {
type CheckboxGroupItemDataSet,
useCheckboxGroupItemContext,
} from "./checkbox-group-item-context";
import { mergeDefaultProps } from "@kobalte/utils";

export interface CheckboxGroupItemDescriptionOptions
extends CheckboxDescriptionOptions {}
Expand All @@ -40,6 +41,15 @@ export function CheckboxGroupItemDescription<T extends ValidComponent = "div">(
) {
const context = useCheckboxGroupItemContext();

const mergedProps = mergeDefaultProps(
{
id: context.generateId("description"),
},
props as CheckboxGroupItemDescriptionProps,
);

createEffect(() => onCleanup(context.registerDescription(mergedProps.id)));

return (
<FormControlDescription<
Component<
Expand All @@ -50,7 +60,7 @@ export function CheckboxGroupItemDescription<T extends ValidComponent = "div">(
>
>
{...context.dataset()}
{...(props as CheckboxGroupItemDescriptionProps)}
{...mergedProps}
/>
);
}
60 changes: 51 additions & 9 deletions packages/core/src/checkbox-group/checkbox-group-item-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
createEffect,
createSignal,
on,
onCleanup,
splitProps,
} from "solid-js";

Expand Down Expand Up @@ -78,13 +79,16 @@ export function CheckboxGroupItemInput<T extends ValidComponent = "input">(
props as CheckboxGroupItemInputProps,
);

const [local, formControlFieldProps, others] = splitProps(
const [local, others] = splitProps(
mergedProps,
["ref", "style", "onChange", "onFocus", "onBlur"],
["ref", "style", "onChange", "onFocus", "onBlur",
"aria-labelledby",
"aria-describedby",
"aria-label"
],
FORM_CONTROL_FIELD_PROP_NAMES,
);

const { fieldProps } = createFormControlField(formControlFieldProps);

const [isInternalChangeEvent, setIsInternalChangeEvent] = createSignal(false);

Expand Down Expand Up @@ -159,6 +163,45 @@ export function CheckboxGroupItemInput<T extends ValidComponent = "input">(
),
);

const ariaLabel = () => {
return (
[
local["aria-label"],
context.labelId(),
]
.filter(Boolean)
.join(" ") || undefined
);
}
const ariaLabelledBy = () => {
return (
[
local["aria-labelledby"],
context.labelId(),
// If there is both an aria-label and aria-labelledby, add the input itself has an aria-labelledby
local["aria-labelledby"] != null && others["aria-label"] != null
? others.id
: undefined,
]
.filter(Boolean)
.join(" ") || undefined
);
};

const ariaDescribedBy = () => {
return (
[
local["aria-describedby"],
context.descriptionId(),
checkboxGroupContext.ariaDescribedBy(),
]
.filter(Boolean)
.join(" ") || undefined
);
};

createEffect(() => onCleanup(context.registerInput(others.id!)));

return (
<Polymorphic<CheckboxGroupItemInputRenderProps>
as="input"
Expand All @@ -167,22 +210,21 @@ export function CheckboxGroupItemInput<T extends ValidComponent = "input">(
ref = el;
}, local.ref)}
type="checkbox"
id={fieldProps.id()}
name={formControlContext.name()}
value={context.value()}
checked={context.checked()}
required={formControlContext.isRequired()}
disabled={formControlContext.isDisabled()}
disabled={context.isDisabled()}
readonly={formControlContext.isReadOnly()}
style={combineStyle(visuallyHiddenStyles, local.style)}
aria-label={fieldProps.ariaLabel()}
aria-labelledby={fieldProps.ariaLabelledBy()}
aria-describedby={fieldProps.ariaDescribedBy()}
aria-label={ariaLabel()}
aria-labelledby={ariaLabelledBy()}
aria-describedby={ariaDescribedBy()}
aria-invalid={
formControlContext.validationState() === "invalid" || undefined
}
aria-required={formControlContext.isRequired()}
aria-disabled={formControlContext.isDisabled()}
aria-disabled={context.isDisabled()}
aria-readonly={formControlContext.isReadOnly()}
onChange={onChange}
onFocus={onFocus}
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/checkbox-group/checkbox-group-item-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
type CheckboxGroupItemDataSet,
useCheckboxGroupItemContext,
} from "./checkbox-group-item-context";
import { mergeDefaultProps } from "@kobalte/utils";

export interface CheckboxGroupItemLabelOptions extends CheckboxLabelOptions {}

Expand All @@ -44,6 +45,15 @@ export function CheckboxGroupItemLabel<T extends ValidComponent = "label">(
) {
const context = useCheckboxGroupItemContext();

const mergedProps = mergeDefaultProps(
{
id: context.generateId("label"),
},
props as CheckboxGroupItemLabelProps,
);

createEffect(() => onCleanup(context.registerLabel(mergedProps.id!)));

return (
<FormControlLabel<
Component<
Expand All @@ -54,7 +64,7 @@ export function CheckboxGroupItemLabel<T extends ValidComponent = "label">(
>
>
{...context.dataset()}
{...(props as CheckboxGroupItemLabelProps)}
{...mergedProps}
/>
);
}
56 changes: 38 additions & 18 deletions packages/core/src/checkbox-group/checkbox-group-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ import {
FORM_CONTROL_PROP_NAMES,
FormControlContext,
createFormControl,
useFormControlContext,
} from "../form-control";
import {
type ElementOf,
Polymorphic,
type PolymorphicProps,
} from "../polymorphic";
import { createFormResetListener, createToggleState } from "../primitives";
import { createFormResetListener, createRegisterId, createToggleState } from "../primitives";
import { useCheckboxGroupContext } from "./checkbox-group-context";
import {
CheckboxGroupItemContext,
Expand Down Expand Up @@ -75,8 +76,13 @@ export function CheckboxGroupItem<T extends ValidComponent = "div">(
) {
let ref: HTMLElement | undefined;

const defaultId = `item-${createUniqueId()}`;
const checkboxGroupContext = useCheckboxGroupContext();
const formControlContext = useFormControlContext();

const defaultId = `${formControlContext.generateId(
"item",
)}-${createUniqueId()}`;


const mergedProps = mergeDefaultProps(
{
Expand All @@ -96,29 +102,17 @@ export function CheckboxGroupItem<T extends ValidComponent = "div">(
"indeterminate",
"onChange",
"onPointerDown",
"disabled"
],
FORM_CONTROL_PROP_NAMES,
);

const [inputId, setInputId] = createSignal<string>();
const [labelId, setLabelId] = createSignal<string>();
const [descriptionId, setDescriptionId] = createSignal<string>();
const [inputRef, setInputRef] = createSignal<HTMLInputElement>();
const [isFocused, setIsFocused] = createSignal(false);

const { formControlContext } = createFormControl(formControlProps);

const state = createToggleState({
isSelected: () =>
checkboxGroupContext.isSelectedValue(local.value ?? "") ||
local.checked ||
false,
defaultIsSelected: () =>
checkboxGroupContext.isSelectedValue(local.value ?? "") ||
local.defaultChecked ||
false,
onSelectedChange: (selected) => local.onChange?.(selected),
isDisabled: () => formControlContext.isDisabled(),
isReadOnly: () => formControlContext.isReadOnly(),
});

createFormResetListener(
() => ref,
() =>
Expand All @@ -140,9 +134,28 @@ export function CheckboxGroupItem<T extends ValidComponent = "div">(
}
};

const isDisabled = createMemo(() => {
return local.disabled || formControlContext.isDisabled() || false;
});

const state = createToggleState({
isSelected: () =>
checkboxGroupContext.isSelectedValue(local.value ?? "") ||
local.checked ||
false,
defaultIsSelected: () =>
checkboxGroupContext.isSelectedValue(local.value ?? "") ||
local.defaultChecked ||
false,
onSelectedChange: (selected) => local.onChange?.(selected),
isDisabled,
isReadOnly: () => formControlContext.isReadOnly(),
});

const dataset: Accessor<CheckboxGroupItemDataSet> = createMemo(() => ({
"data-checked": state.isSelected() ? "" : undefined,
"data-indeterminate": local.indeterminate ? "" : undefined,
"data-disabled": isDisabled() ? "": undefined
}));

const context: CheckboxGroupItemContextValue = {
Expand All @@ -159,6 +172,13 @@ export function CheckboxGroupItem<T extends ValidComponent = "div">(
setIsChecked: (isChecked) => state.setIsSelected(isChecked),
setIsFocused,
setInputRef,
isDisabled,
inputId,
labelId,
descriptionId,
registerInput: createRegisterId(setInputId),
registerLabel: createRegisterId(setLabelId),
registerDescription: createRegisterId(setDescriptionId),
};

return (
Expand Down
Loading

0 comments on commit a0c61ae

Please sign in to comment.