Skip to content

Commit

Permalink
next: Documentation work (#622)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Jul 29, 2024
1 parent bb0d9d7 commit f0c10fe
Show file tree
Hide file tree
Showing 181 changed files with 1,799 additions and 1,006 deletions.
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

0 comments on commit f0c10fe

Please sign in to comment.