Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next: Documentation work #622

Merged
merged 20 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,11 @@ They also need to be flexible enough to allow for reusing the same component whi
---

Should we embrace the [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState) API? Something to think about.

---

We need to expose the different `open` states via snippet props for all the `forceMount`-able components to work with Svelte and other transition/animation libs.

---

We need to handle `invalid` state for the `DateRangeField` component.
16 changes: 8 additions & 8 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ export default config({ svelte: true, ignores: [...DEFAULT_IGNORES, ...ignores]
.override("antfu/typescript/rules", {
rules: {
"ts/consistent-type-definitions": "off",
"ts/ban-types": [
"error",
{
types: {
"{}": false,
},
},
],
"unused-imports/no-unused-imports": "off",
"unused-imports/no-unused-vars": "off",
"ts/no-unused-expressions": "off",
"no-unused-expressions": "off",
"ts/no-empty-object-type": "off",
},
})
.override("antfu/javascript/rules", {
rules: {
"no-unused-expressions": "off",
"unused-imports/no-unused-imports": "off",
},
})
.override("huntabyte/svelte/rules", {
rules: {
"svelte/no-at-html-tags": "off",
"unused-imports/no-unused-imports": "off",
"unused-imports/no-unused-vars": "off",
},
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"build:packages": "pnpm -F \"./packages/**\" --parallel build",
"check": "pnpm build:packages && pnpm -r check",
"ci:publish": "pnpm build:packages && changeset publish",
"dev": "pnpm -F \"./packages/**\" svelte-kit sync && pnpm -r --parallel dev",
"dev": "pnpm -F \"./packages/**\" svelte-kit sync && pnpm -r --parallel --reporter append-only --color dev",
"format": "prettier --write .",
"lint": "prettier --check . && eslint .",
"lint:fix": "eslint --fix .",
Expand Down
1 change: 1 addition & 0 deletions packages/bits-ui/other/setupTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ vi.mock("$app/stores", (): typeof stores => {
// eslint-disable-next-line ts/no-require-imports
globalThis.ResizeObserver = require("resize-observer-polyfill");
Element.prototype.scrollIntoView = () => {};
// eslint-disable-next-line ts/no-explicit-any
Element.prototype.hasPointerCapture = (() => {}) as any;

// @ts-expect-error - shut it
Expand Down
49 changes: 27 additions & 22 deletions packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import type { Box, ReadableBoxedValues, WritableBoxedValues } from "$lib/internal/box.svelte.js";
import type { WithRefProps } from "$lib/internal/types.js";
import { afterTick } from "$lib/internal/afterTick.js";
import {
type Box,
type ReadableBoxedValues,
type WithRefProps,
type WritableBoxedValues,
afterTick,
getAriaDisabled,
getAriaExpanded,
getDataDisabled,
getDataOpenClosed,
getDataOrientation,
kbd,
useRefById,
} from "$lib/internal/index.js";
} from "$lib/internal/attrs.js";
import { kbd } from "$lib/internal/kbd.js";
import { useRefById } from "$lib/internal/useRefById.svelte.js";
import { type UseRovingFocusReturn, useRovingFocus } from "$lib/internal/useRovingFocus.svelte.js";
import type { Orientation } from "$lib/shared/index.js";
import { createContext } from "$lib/internal/createContext.js";
Expand Down Expand Up @@ -144,7 +142,7 @@ export class AccordionItemState {
value: AccordionItemStateProps["value"];
disabled: AccordionItemStateProps["disabled"];
root: AccordionState;
isSelected = $derived.by(() => this.root.includesItem(this.value.current));
isActive = $derived.by(() => this.root.includesItem(this.value.current));
isDisabled = $derived.by(() => this.disabled.current || this.root.disabled.current);

constructor(props: AccordionItemStateProps) {
Expand Down Expand Up @@ -176,12 +174,15 @@ export class AccordionItemState {
return new AccordionHeaderState(props, this);
}

props = $derived.by(() => ({
id: this.#id.current,
[ACCORDION_ITEM_ATTR]: "",
"data-state": getDataOpenClosed(this.isSelected),
"data-disabled": getDataDisabled(this.isDisabled),
}));
props = $derived.by(
() =>
({
id: this.#id.current,
"data-state": getDataOpenClosed(this.isActive),
"data-disabled": getDataDisabled(this.isDisabled),
[ACCORDION_ITEM_ATTR]: "",
}) as const
);
}

//
Expand All @@ -190,7 +191,7 @@ export class AccordionItemState {

type AccordionTriggerStateProps = WithRefProps<
ReadableBoxedValues<{
disabled: boolean;
disabled: boolean | null | undefined;
}>
>;

Expand Down Expand Up @@ -240,10 +241,10 @@ class AccordionTriggerState {
({
id: this.#id.current,
disabled: this.#isDisabled,
"aria-expanded": getAriaExpanded(this.#itemState.isSelected),
"aria-expanded": getAriaExpanded(this.#itemState.isActive),
"aria-disabled": getAriaDisabled(this.#isDisabled),
"data-disabled": getDataDisabled(this.#isDisabled),
"data-state": getDataOpenClosed(this.#itemState.isSelected),
"data-state": getDataOpenClosed(this.#itemState.isActive),
"data-orientation": getDataOrientation(this.#root.orientation.current),
[ACCORDION_TRIGGER_ATTR]: "",
tabindex: 0,
Expand Down Expand Up @@ -273,12 +274,12 @@ class AccordionContentState {
#height = $state(0);
#forceMount: AccordionContentStateProps["forceMount"];

present = $derived.by(() => this.#forceMount.current || this.item.isSelected);
present = $derived.by(() => this.#forceMount.current || this.item.isActive);

constructor(props: AccordionContentStateProps, item: AccordionItemState) {
this.item = item;
this.#forceMount = props.forceMount;
this.#isMountAnimationPrevented = this.item.isSelected;
this.#isMountAnimationPrevented = this.item.isActive;
this.#id = props.id;
this.#ref = props.ref;

Expand Down Expand Up @@ -328,11 +329,15 @@ class AccordionContentState {
});
}

snippetProps = $derived.by(() => ({
open: this.item.isActive,
}));

props = $derived.by(
() =>
({
id: this.#id.current,
"data-state": getDataOpenClosed(this.item.isSelected),
"data-state": getDataOpenClosed(this.item.isActive),
"data-disabled": getDataDisabled(this.item.isDisabled),
"data-orientation": getDataOrientation(this.item.root.orientation.current),
[ACCORDION_CONTENT_ATTR]: "",
Expand Down Expand Up @@ -375,7 +380,7 @@ class AccordionHeaderState {
role: "heading",
"aria-level": this.#level.current,
"data-heading-level": this.#level.current,
"data-state": getDataOpenClosed(this.#item.isSelected),
"data-state": getDataOpenClosed(this.#item.isActive),
"data-orientation": getDataOrientation(this.#item.root.orientation.current),
[ACCORDION_HEADER_ATTR]: "",
}) as const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import { useAccordionContent } from "../accordion.svelte.js";
import type { AccordionContentProps } from "../types.js";
import { PresenceLayer } from "$lib/bits/utilities/presence-layer/index.js";
import { mergeProps, useId } from "$lib/internal/index.js";
import { mergeProps } from "$lib/internal/mergeProps.js";
import { useId } from "$lib/internal/useId.js";

let {
child,
Expand All @@ -27,15 +28,16 @@
<PresenceLayer forceMount={true} present={contentState.present} {id}>
{#snippet presence({ present })}
{@const mergedProps = mergeProps(restProps, contentState.props, {
hidden: !present.current,
hidden: forceMount ? undefined : !present.current,
})}
{#if child}
{@render child({
props: mergedProps,
...contentState.snippetProps,
})}
{:else}
<div {...mergedProps}>
{@render children?.()}
{@render children?.(contentState.snippetProps)}
</div>
{/if}
{/snippet}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
let {
id = useId(),
disabled = false,
value,
value = useId(),
children,
child,
ref = $bindable(null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import { box } from "svelte-toolbelt";
import type { AccordionTriggerProps } from "../types.js";
import { useAccordionTrigger } from "../accordion.svelte.js";
import { mergeProps, useId } from "$lib/internal/index.js";
import { mergeProps } from "$lib/internal/mergeProps.js";
import { useId } from "$lib/internal/useId.js";

let {
disabled = false,
Expand Down
58 changes: 37 additions & 21 deletions packages/bits-ui/src/lib/bits/accordion/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { EventCallback, OnChangeFn, WithChild, Without } from "$lib/internal/index.js";
import type { OnChangeFn, WithChild, Without } from "$lib/internal/types.js";
import type { PrimitiveButtonAttributes, PrimitiveDivAttributes } from "$lib/shared/attributes.js";
import type { Orientation } from "$lib/shared/index.js";

Expand Down Expand Up @@ -79,42 +79,58 @@ export type AccordionRootPropsWithoutHTML =
export type AccordionRootProps = AccordionRootPropsWithoutHTML &
Without<PrimitiveDivAttributes, AccordionRootPropsWithoutHTML>;

export type AccordionTriggerPropsWithoutHTML = WithChild<{
/**
* Whether the trigger for the accordion item is disabled or not.
*
* @defaultValue false
*/
disabled?: boolean | null | undefined;
}>;
export type AccordionTriggerPropsWithoutHTML = WithChild;

export type AccordionTriggerProps = AccordionTriggerPropsWithoutHTML &
Omit<PrimitiveButtonAttributes, "disabled" | "onclick" | "onkeydown">;
Without<PrimitiveButtonAttributes, AccordionTriggerPropsWithoutHTML>;

export type AccordionItemContext = {
value: string;
disabled: boolean;
};

export type AccordionContentPropsWithoutHTML = WithChild<{
export type AccordionContentSnippetProps = {
/**
* Whether to forcefully mount the content, regardless of the open state.
* This is useful if you want to use Svelte transitions for the content.
* Whether the accordion content is active/open or not.
*/
forceMount?: boolean;
}>;
open: boolean;
};

export type AccordionContentPropsWithoutHTML = WithChild<
{
/**
* Whether to forcefully mount the content, regardless of the open state.
* This is useful if you want to use Svelte transitions for the content.
*
* @defaultValue `true`
*/
forceMount?: boolean;
},
AccordionContentSnippetProps
>;

export type AccordionContentProps = AccordionContentPropsWithoutHTML &
Without<PrimitiveDivAttributes, AccordionContentPropsWithoutHTML>;

export type AccordionItemPropsWithoutHTML = WithChild<{
value: string;
/**
* The value of the accordion item. This is used to identify if the item is open or closed.
* If not provided, a unique ID will be generated for this value.
*/
value?: string;

/**
* Whether the accordion item is disabled, which prevents users from interacting with it.
*
* @defaultValue `false`
*/
disabled?: boolean;
}>;

export type AccordionItemProps = AccordionItemPropsWithoutHTML & PrimitiveDivAttributes;

export type AccordionHeaderPropsWithoutHTML = WithChild<{
/**
* The level of the accordion header, applied to the element's `aria-level` attribute.
* This is used to indicate the hierarchical relationship between the accordion items.
*
* @defaultValue `3`
*/
level?: 1 | 2 | 3 | 4 | 5 | 6;
}>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
onDestroyAutoFocus = noop,
onEscapeKeydown = noop,
onMountAutoFocus = noop,
preventScroll = true,
...restProps
}: ContentProps = $props();

Expand All @@ -37,7 +38,7 @@

<PresenceLayer {...mergedProps} present={contentState.root.open.current || forceMount}>
{#snippet presence({ present })}
<ScrollLock preventScroll={true} />
<ScrollLock {preventScroll} />
<FocusScope
loop
trapped={present.current}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useRefById, type ReadableBoxedValues, type WithRefProps } from "$lib/internal/index.js";
import { useRefById } from "$lib/internal/useRefById.svelte.js";
import type { ReadableBoxedValues } from "$lib/internal/box.svelte.js";
import type { WithRefProps } from "$lib/internal/types.js";

const ASPECT_RATIO_ROOT_ATTR = "data-aspect-ratio-root";

Expand Down
2 changes: 1 addition & 1 deletion packages/bits-ui/src/lib/bits/aspect-ratio/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { WithChild, Without } from "$lib/internal/index.js";
import type { WithChild, Without } from "$lib/internal/types.js";
import type { PrimitiveDivAttributes } from "$lib/shared/attributes.js";

export type AspectRatioPropsWithoutHTML = WithChild<{
Expand Down
2 changes: 2 additions & 0 deletions packages/bits-ui/src/lib/bits/avatar/avatar.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class AvatarImageState {
style: {
display: this.root.loadingStatus.current === "loaded" ? "block" : "none",
},
"data-status": this.root.loadingStatus.current,
[AVATAR_IMAGE_ATTR]: "",
src: this.src.current,
}) as const
Expand Down Expand Up @@ -148,6 +149,7 @@ class AvatarFallbackState {
style: {
display: this.root.loadingStatus.current === "loaded" ? "none" : undefined,
},
"data-status": this.root.loadingStatus.current,
[AVATAR_FALLBACK_ATTR]: "",
}) as const
);
Expand Down
2 changes: 1 addition & 1 deletion packages/bits-ui/src/lib/bits/avatar/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OnChangeFn, WithChild, Without } from "$lib/internal/index.js";
import type { OnChangeFn, WithChild, Without } from "$lib/internal/types.js";
import type {
PrimitiveDivAttributes,
PrimitiveImgAttributes,
Expand Down
Loading