INIT
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Hunter Johnston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
# Bits UI
|
||||
|
||||
<!-- automd:badges license name="bits-ui" color="pink" github="huntabyte/bits-ui" -->
|
||||
|
||||
[](https://npmjs.com/package/bits-ui)
|
||||
[](https://npmjs.com/package/bits-ui)
|
||||
[](https://github.com/huntabyte/bits-ui/blob/main/LICENSE)
|
||||
[](https://discord.gg/fdXy3Sk8Gq)
|
||||
|
||||
<img style="max-width: 100%" alt="hero" src="https://github.com/user-attachments/assets/19cac792-6a93-4289-b9c7-647794a7de79" />
|
||||
|
||||
**Bits UI** – the headless components for Svelte.
|
||||
|
||||
Flexible, unstyled, and accessible primitives that provide the foundation for building your own high-quality component library.
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit https://bits-ui.com/docs to view the documentation.
|
||||
|
||||
## Credits
|
||||
|
||||
- [Bitworks](https://bitworks.cz) - The design team behind the Bits UI documentation and example components.
|
||||
- [Melt UI](https://melt-ui.com) - A powerful builder API that inspired the internal architecture of Bits UI.
|
||||
- [Radix UI](https://radix-ui.com) - The incredible headless component APIs that we've taken heavy inspiration from.
|
||||
- [React Spectrum](https://react-spectrum.adobe.com) - An incredible collection of headless components we've taken inspiration from.
|
||||
|
||||
## Sponsors
|
||||
|
||||
This project is supported by the following beautiful people/organizations:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/sponsors/huntabyte">
|
||||
<img src='https://github.com/huntabyte/static/blob/main/sponsors.svg?raw=true' alt="Logos from Sponsors" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## License
|
||||
|
||||
<!-- automd:contributors license=MIT author="huntabyte" github="huntabyte/bits-ui" -->
|
||||
|
||||
Published under the [MIT](https://github.com/huntabyte/bits-ui/blob/main/LICENSE) license.
|
||||
Built by [@huntabyte](https://github.com/huntabyte) and [community](https://github.com/huntabyte/bits-ui/graphs/contributors). Designed by [Pavel Stianko](https://x.com/pavel_stianko) 💛
|
||||
<br><br>
|
||||
<a href="https://github.com/huntabyte/bits-ui/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=huntabyte/bits-ui" />
|
||||
</a>
|
||||
|
||||
<!-- /automd -->
|
||||
|
||||
## Community
|
||||
|
||||
Join the Discord server to ask questions, find collaborators, or just say hi!
|
||||
|
||||
<a href="https://discord.gg/fdXy3Sk8Gq" alt="Svecosystem Discord community">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://invidget.switchblade.xyz/fdXy3Sk8Gq">
|
||||
<img alt="Svecosystem Discord community" src="https://invidget.switchblade.xyz/fdXy3Sk8Gq?theme=light">
|
||||
</picture>
|
||||
</a>
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// oxlint-disable no-var
|
||||
import type { ReadableBox } from "svelte-toolbelt";
|
||||
import type { DismissibleLayerState } from "./bits/utilities/dismissible-layer/use-dismissable-layer.svelte.ts";
|
||||
import type { InteractOutsideBehaviorType } from "./bits/utilities/dismissible-layer/types.ts";
|
||||
import type { EscapeLayerState } from "./bits/utilities/escape-layer/use-escape-layer.svelte.ts";
|
||||
import type { EscapeBehaviorType } from "./bits/utilities/escape-layer/types.ts";
|
||||
import type { TextSelectionLayerState } from "./bits/utilities/text-selection-layer/use-text-selection-layer.svelte.ts";
|
||||
|
||||
declare global {
|
||||
var bitsDismissableLayers: Map<DismissibleLayerState, ReadableBox<InteractOutsideBehaviorType>>;
|
||||
var bitsEscapeLayers: Map<EscapeLayerState, ReadableBox<EscapeBehaviorType>>;
|
||||
var bitsTextSelectionLayers: Map<TextSelectionLayerState, ReadableBox<boolean>>;
|
||||
var bitsIdCounter: { current: number };
|
||||
var bitsBodyLockStackCount: {
|
||||
readonly map: SvelteMap<string, boolean>;
|
||||
resetBodyStyle: () => void;
|
||||
};
|
||||
var bitsAnimationsDisabled: boolean;
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
import { type Box, type ReadableBoxedValues, type WritableBoxedValues } from "svelte-toolbelt";
|
||||
import type { BitsKeyboardEvent, BitsMouseEvent, RefAttachment, WithRefOpts } from "../../internal/types.js";
|
||||
import type { Orientation } from "../../shared/index.js";
|
||||
import { RovingFocusGroup } from "../../internal/roving-focus-group.js";
|
||||
import { PresenceManager } from "../../internal/presence-manager.svelte.js";
|
||||
interface AccordionBaseStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
disabled: boolean;
|
||||
orientation: Orientation;
|
||||
loop: boolean;
|
||||
}> {
|
||||
}
|
||||
interface AccordionSingleStateOpts extends AccordionBaseStateOpts, WritableBoxedValues<{
|
||||
value: string;
|
||||
}> {
|
||||
}
|
||||
interface AccordionMultiStateOpts extends AccordionBaseStateOpts, WritableBoxedValues<{
|
||||
value: string[];
|
||||
}> {
|
||||
}
|
||||
type AccordionRoot = AccordionSingleState | AccordionMultiState;
|
||||
interface AccordionItemStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
value: string;
|
||||
disabled: boolean;
|
||||
}> {
|
||||
rootState: AccordionRoot;
|
||||
}
|
||||
interface AccordionTriggerStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
disabled: boolean | null | undefined;
|
||||
tabindex: number;
|
||||
}> {
|
||||
}
|
||||
interface AccordionContentStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
forceMount: boolean;
|
||||
hiddenUntilFound: boolean;
|
||||
}> {
|
||||
}
|
||||
interface AccordionHeaderStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
level: 1 | 2 | 3 | 4 | 5 | 6;
|
||||
}> {
|
||||
}
|
||||
interface AccordionRootStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
disabled: boolean;
|
||||
orientation: Orientation;
|
||||
loop: boolean;
|
||||
}> {
|
||||
type: "single" | "multiple";
|
||||
value: Box<string> | Box<string[]>;
|
||||
}
|
||||
declare abstract class AccordionBaseState {
|
||||
readonly opts: AccordionBaseStateOpts;
|
||||
readonly rovingFocusGroup: RovingFocusGroup;
|
||||
abstract readonly isMulti: boolean;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AccordionBaseStateOpts);
|
||||
abstract includesItem(item: string): boolean;
|
||||
abstract toggleItem(item: string): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-orientation": Orientation;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
};
|
||||
}
|
||||
declare class AccordionSingleState extends AccordionBaseState {
|
||||
readonly opts: AccordionSingleStateOpts;
|
||||
readonly isMulti: false;
|
||||
constructor(opts: AccordionSingleStateOpts);
|
||||
includesItem(item: string): boolean;
|
||||
toggleItem(item: string): void;
|
||||
}
|
||||
declare class AccordionMultiState extends AccordionBaseState {
|
||||
#private;
|
||||
readonly isMulti: true;
|
||||
constructor(props: AccordionMultiStateOpts);
|
||||
includesItem(item: string): boolean;
|
||||
toggleItem(item: string): void;
|
||||
}
|
||||
export declare class AccordionRootState {
|
||||
static create(props: AccordionRootStateOpts): AccordionRoot;
|
||||
}
|
||||
export declare class AccordionItemState {
|
||||
static create(props: Omit<AccordionItemStateOpts, "rootState">): AccordionItemState;
|
||||
readonly opts: AccordionItemStateOpts;
|
||||
readonly root: AccordionRoot;
|
||||
readonly isActive: boolean;
|
||||
readonly isDisabled: boolean;
|
||||
readonly attachment: RefAttachment;
|
||||
contentNode: HTMLElement | null;
|
||||
contentPresence: PresenceManager;
|
||||
constructor(opts: AccordionItemStateOpts);
|
||||
updateValue(): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-state": "open" | "closed";
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-orientation": Orientation;
|
||||
};
|
||||
}
|
||||
export declare class AccordionTriggerState {
|
||||
#private;
|
||||
readonly opts: AccordionTriggerStateOpts;
|
||||
readonly itemState: AccordionItemState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AccordionTriggerStateOpts, itemState: AccordionItemState);
|
||||
static create(props: AccordionTriggerStateOpts): AccordionTriggerState;
|
||||
onclick(e: BitsMouseEvent): void;
|
||||
onkeydown(e: BitsKeyboardEvent): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly disabled: boolean;
|
||||
readonly "aria-expanded": "true" | "false";
|
||||
readonly "aria-disabled": "true" | "false";
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-state": "open" | "closed";
|
||||
readonly "data-orientation": Orientation;
|
||||
readonly tabindex: number;
|
||||
readonly onclick: (e: BitsMouseEvent) => void;
|
||||
readonly onkeydown: (e: BitsKeyboardEvent) => void;
|
||||
};
|
||||
}
|
||||
export declare class AccordionContentState {
|
||||
#private;
|
||||
readonly opts: AccordionContentStateOpts;
|
||||
readonly item: AccordionItemState;
|
||||
readonly attachment: RefAttachment;
|
||||
readonly open: boolean;
|
||||
constructor(opts: AccordionContentStateOpts, item: AccordionItemState);
|
||||
static create(props: AccordionContentStateOpts): AccordionContentState;
|
||||
get shouldRender(): boolean;
|
||||
readonly snippetProps: {
|
||||
open: boolean;
|
||||
};
|
||||
readonly props: {
|
||||
readonly hidden: boolean | "until-found" | undefined;
|
||||
readonly id: string;
|
||||
readonly "data-state": "open" | "closed";
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-orientation": Orientation;
|
||||
readonly style: {
|
||||
readonly "--bits-accordion-content-height": `${number}px`;
|
||||
readonly "--bits-accordion-content-width": `${number}px`;
|
||||
};
|
||||
};
|
||||
}
|
||||
export declare class AccordionHeaderState {
|
||||
readonly opts: AccordionHeaderStateOpts;
|
||||
readonly item: AccordionItemState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AccordionHeaderStateOpts, item: AccordionItemState);
|
||||
static create(props: AccordionHeaderStateOpts): AccordionHeaderState;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly role: "heading";
|
||||
readonly "aria-level": 1 | 2 | 3 | 4 | 5 | 6;
|
||||
readonly "data-heading-level": 1 | 2 | 3 | 4 | 5 | 6;
|
||||
readonly "data-state": "open" | "closed";
|
||||
readonly "data-orientation": Orientation;
|
||||
};
|
||||
}
|
||||
export {};
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
import { afterTick, attachRef, boxWith, } from "svelte-toolbelt";
|
||||
import { Context, watch } from "runed";
|
||||
import { boolToStr, boolToEmptyStrOrUndef, getDataOpenClosed } from "../../internal/attrs.js";
|
||||
import { kbd } from "../../internal/kbd.js";
|
||||
import { createBitsAttrs } from "../../internal/attrs.js";
|
||||
import { RovingFocusGroup } from "../../internal/roving-focus-group.js";
|
||||
import { on } from "svelte/events";
|
||||
import { PresenceManager } from "../../internal/presence-manager.svelte.js";
|
||||
const accordionAttrs = createBitsAttrs({
|
||||
component: "accordion",
|
||||
parts: ["root", "trigger", "content", "item", "header"],
|
||||
});
|
||||
const AccordionRootContext = new Context("Accordion.Root");
|
||||
const AccordionItemContext = new Context("Accordion.Item");
|
||||
class AccordionBaseState {
|
||||
opts;
|
||||
rovingFocusGroup;
|
||||
attachment;
|
||||
constructor(opts) {
|
||||
this.opts = opts;
|
||||
this.rovingFocusGroup = new RovingFocusGroup({
|
||||
rootNode: this.opts.ref,
|
||||
candidateAttr: accordionAttrs.trigger,
|
||||
loop: this.opts.loop,
|
||||
orientation: this.opts.orientation,
|
||||
});
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-orientation": this.opts.orientation.current,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.opts.disabled.current),
|
||||
[accordionAttrs.root]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
class AccordionSingleState extends AccordionBaseState {
|
||||
opts;
|
||||
isMulti = false;
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
this.opts = opts;
|
||||
this.includesItem = this.includesItem.bind(this);
|
||||
this.toggleItem = this.toggleItem.bind(this);
|
||||
}
|
||||
includesItem(item) {
|
||||
return this.opts.value.current === item;
|
||||
}
|
||||
toggleItem(item) {
|
||||
this.opts.value.current = this.includesItem(item) ? "" : item;
|
||||
}
|
||||
}
|
||||
class AccordionMultiState extends AccordionBaseState {
|
||||
#value;
|
||||
isMulti = true;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.#value = props.value;
|
||||
this.includesItem = this.includesItem.bind(this);
|
||||
this.toggleItem = this.toggleItem.bind(this);
|
||||
}
|
||||
includesItem(item) {
|
||||
return this.#value.current.includes(item);
|
||||
}
|
||||
toggleItem(item) {
|
||||
this.#value.current = this.includesItem(item)
|
||||
? this.#value.current.filter((v) => v !== item)
|
||||
: [...this.#value.current, item];
|
||||
}
|
||||
}
|
||||
export class AccordionRootState {
|
||||
static create(props) {
|
||||
const { type, ...rest } = props;
|
||||
const rootState = type === "single"
|
||||
? new AccordionSingleState(rest)
|
||||
: new AccordionMultiState(rest);
|
||||
return AccordionRootContext.set(rootState);
|
||||
}
|
||||
}
|
||||
export class AccordionItemState {
|
||||
static create(props) {
|
||||
return AccordionItemContext.set(new AccordionItemState({ ...props, rootState: AccordionRootContext.get() }));
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
isActive = $derived.by(() => this.root.includesItem(this.opts.value.current));
|
||||
isDisabled = $derived.by(() => this.opts.disabled.current || this.root.opts.disabled.current);
|
||||
attachment;
|
||||
contentNode = $state(null);
|
||||
contentPresence;
|
||||
constructor(opts) {
|
||||
this.opts = opts;
|
||||
this.root = opts.rootState;
|
||||
this.updateValue = this.updateValue.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
this.contentPresence = new PresenceManager({
|
||||
ref: boxWith(() => this.contentNode),
|
||||
open: boxWith(() => this.isActive),
|
||||
});
|
||||
}
|
||||
updateValue() {
|
||||
this.root.toggleItem(this.opts.value.current);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-state": getDataOpenClosed(this.isActive),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.isDisabled),
|
||||
"data-orientation": this.root.opts.orientation.current,
|
||||
[accordionAttrs.item]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class AccordionTriggerState {
|
||||
opts;
|
||||
itemState;
|
||||
#root;
|
||||
#isDisabled = $derived.by(() => this.opts.disabled.current ||
|
||||
this.itemState.opts.disabled.current ||
|
||||
this.#root.opts.disabled.current);
|
||||
attachment;
|
||||
constructor(opts, itemState) {
|
||||
this.opts = opts;
|
||||
this.itemState = itemState;
|
||||
this.#root = itemState.root;
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.onkeydown = this.onkeydown.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
static create(props) {
|
||||
return new AccordionTriggerState(props, AccordionItemContext.get());
|
||||
}
|
||||
onclick(e) {
|
||||
if (this.#isDisabled || e.button !== 0) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
this.itemState.updateValue();
|
||||
}
|
||||
onkeydown(e) {
|
||||
if (this.#isDisabled)
|
||||
return;
|
||||
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
|
||||
e.preventDefault();
|
||||
this.itemState.updateValue();
|
||||
return;
|
||||
}
|
||||
this.#root.rovingFocusGroup.handleKeydown(this.opts.ref.current, e);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
disabled: this.#isDisabled,
|
||||
"aria-expanded": boolToStr(this.itemState.isActive),
|
||||
"aria-disabled": boolToStr(this.#isDisabled),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.#isDisabled),
|
||||
"data-state": getDataOpenClosed(this.itemState.isActive),
|
||||
"data-orientation": this.#root.opts.orientation.current,
|
||||
[accordionAttrs.trigger]: "",
|
||||
tabindex: this.opts.tabindex.current,
|
||||
onclick: this.onclick,
|
||||
onkeydown: this.onkeydown,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class AccordionContentState {
|
||||
opts;
|
||||
item;
|
||||
attachment;
|
||||
#originalStyles = undefined;
|
||||
#isMountAnimationPrevented = false;
|
||||
#dimensions = $state({ width: 0, height: 0 });
|
||||
open = $derived.by(() => {
|
||||
if (this.opts.hiddenUntilFound.current)
|
||||
return this.item.isActive;
|
||||
return this.opts.forceMount.current || this.item.isActive;
|
||||
});
|
||||
constructor(opts, item) {
|
||||
this.opts = opts;
|
||||
this.item = item;
|
||||
this.#isMountAnimationPrevented = this.item.isActive;
|
||||
this.attachment = attachRef(this.opts.ref, (v) => (this.item.contentNode = v));
|
||||
// Prevent mount animations on initial render
|
||||
$effect(() => {
|
||||
const rAF = requestAnimationFrame(() => {
|
||||
this.#isMountAnimationPrevented = false;
|
||||
});
|
||||
return () => cancelAnimationFrame(rAF);
|
||||
});
|
||||
watch.pre([() => this.opts.ref.current, () => this.opts.hiddenUntilFound.current], ([node, hiddenUntilFound]) => {
|
||||
if (!node || !hiddenUntilFound)
|
||||
return;
|
||||
const handleBeforeMatch = () => {
|
||||
if (this.item.isActive)
|
||||
return;
|
||||
// we need to defer opening until after browser completes search highlighting
|
||||
// otherwise the browser will immediately open the accordion
|
||||
// and the search highlighting will not be visible
|
||||
requestAnimationFrame(() => {
|
||||
this.item.updateValue();
|
||||
});
|
||||
};
|
||||
return on(node, "beforematch", handleBeforeMatch);
|
||||
});
|
||||
// Handle dimension updates
|
||||
watch([() => this.open, () => this.opts.ref.current], this.#updateDimensions);
|
||||
}
|
||||
static create(props) {
|
||||
return new AccordionContentState(props, AccordionItemContext.get());
|
||||
}
|
||||
#updateDimensions = ([_, node]) => {
|
||||
if (!node)
|
||||
return;
|
||||
afterTick(() => {
|
||||
const element = this.opts.ref.current;
|
||||
if (!element)
|
||||
return;
|
||||
// store original styles on first run
|
||||
this.#originalStyles ??= {
|
||||
transitionDuration: element.style.transitionDuration,
|
||||
animationName: element.style.animationName,
|
||||
};
|
||||
// temporarily disable animations for measurement
|
||||
element.style.transitionDuration = "0s";
|
||||
element.style.animationName = "none";
|
||||
const rect = element.getBoundingClientRect();
|
||||
this.#dimensions = { width: rect.width, height: rect.height };
|
||||
// restore animations if not initial mount
|
||||
if (!this.#isMountAnimationPrevented && this.#originalStyles) {
|
||||
element.style.transitionDuration = this.#originalStyles.transitionDuration;
|
||||
element.style.animationName = this.#originalStyles.animationName;
|
||||
}
|
||||
});
|
||||
};
|
||||
get shouldRender() {
|
||||
return this.item.contentPresence.shouldRender;
|
||||
}
|
||||
snippetProps = $derived.by(() => ({ open: this.item.isActive }));
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-state": getDataOpenClosed(this.item.isActive),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.item.isDisabled),
|
||||
"data-orientation": this.item.root.opts.orientation.current,
|
||||
[accordionAttrs.content]: "",
|
||||
style: {
|
||||
"--bits-accordion-content-height": `${this.#dimensions.height}px`,
|
||||
"--bits-accordion-content-width": `${this.#dimensions.width}px`,
|
||||
},
|
||||
hidden: this.opts.hiddenUntilFound.current && !this.item.isActive
|
||||
? "until-found"
|
||||
: undefined,
|
||||
...(this.opts.hiddenUntilFound.current && !this.shouldRender
|
||||
? {}
|
||||
: {
|
||||
hidden: this.opts.hiddenUntilFound.current
|
||||
? !this.shouldRender
|
||||
: this.opts.forceMount.current
|
||||
? undefined
|
||||
: !this.shouldRender,
|
||||
}),
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class AccordionHeaderState {
|
||||
opts;
|
||||
item;
|
||||
attachment;
|
||||
constructor(opts, item) {
|
||||
this.opts = opts;
|
||||
this.item = item;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
static create(props) {
|
||||
return new AccordionHeaderState(props, AccordionItemContext.get());
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: "heading",
|
||||
"aria-level": this.opts.level.current,
|
||||
"data-heading-level": this.opts.level.current,
|
||||
"data-state": getDataOpenClosed(this.item.isActive),
|
||||
"data-orientation": this.item.root.opts.orientation.current,
|
||||
[accordionAttrs.header]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import { mergeProps, boxWith } from "svelte-toolbelt";
|
||||
import { AccordionContentState } from "../accordion.svelte.js";
|
||||
import type { AccordionContentProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
forceMount = false,
|
||||
children,
|
||||
hiddenUntilFound = false,
|
||||
...restProps
|
||||
}: AccordionContentProps = $props();
|
||||
|
||||
const contentState = AccordionContentState.create({
|
||||
forceMount: boxWith(() => forceMount),
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
hiddenUntilFound: boxWith(() => hiddenUntilFound),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, contentState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({
|
||||
props: mergedProps,
|
||||
...contentState.snippetProps,
|
||||
})}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { AccordionContentProps } from "../types.js";
|
||||
declare const AccordionContent: import("svelte").Component<AccordionContentProps, {}, "ref">;
|
||||
type AccordionContent = ReturnType<typeof AccordionContent>;
|
||||
export default AccordionContent;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AccordionHeaderProps } from "../types.js";
|
||||
import { AccordionHeaderState } from "../accordion.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
level = 2,
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
...restProps
|
||||
}: AccordionHeaderProps = $props();
|
||||
|
||||
const headerState = AccordionHeaderState.create({
|
||||
id: boxWith(() => id),
|
||||
level: boxWith(() => level),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, headerState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AccordionHeaderProps } from "../types.js";
|
||||
declare const AccordionHeader: import("svelte").Component<AccordionHeaderProps, {}, "ref">;
|
||||
type AccordionHeader = ReturnType<typeof AccordionHeader>;
|
||||
export default AccordionHeader;
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AccordionItemProps } from "../types.js";
|
||||
import { AccordionItemState } from "../accordion.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
const defaultId = createId(uid);
|
||||
|
||||
let {
|
||||
id = defaultId,
|
||||
disabled = false,
|
||||
value = defaultId,
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
...restProps
|
||||
}: AccordionItemProps = $props();
|
||||
|
||||
const itemState = AccordionItemState.create({
|
||||
value: boxWith(() => value),
|
||||
disabled: boxWith(() => disabled),
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, itemState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AccordionItemProps } from "../types.js";
|
||||
declare const AccordionItem: import("svelte").Component<AccordionItemProps, {}, "ref">;
|
||||
type AccordionItem = ReturnType<typeof AccordionItem>;
|
||||
export default AccordionItem;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AccordionTriggerProps } from "../types.js";
|
||||
import { AccordionTriggerState } from "../accordion.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
disabled = false,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
tabindex = 0,
|
||||
children,
|
||||
child,
|
||||
...restProps
|
||||
}: AccordionTriggerProps = $props();
|
||||
|
||||
const triggerState = AccordionTriggerState.create({
|
||||
disabled: boxWith(() => disabled),
|
||||
id: boxWith(() => id),
|
||||
tabindex: boxWith(() => tabindex ?? 0),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, triggerState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button type="button" {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { AccordionTriggerProps } from "../types.js";
|
||||
declare const AccordionTrigger: import("svelte").Component<AccordionTriggerProps, {}, "ref">;
|
||||
type AccordionTrigger = ReturnType<typeof AccordionTrigger>;
|
||||
export default AccordionTrigger;
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<script lang="ts">
|
||||
import { type WritableBox, boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { AccordionRootState } from "../accordion.svelte.js";
|
||||
import type { AccordionRootProps } from "../types.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { watch } from "runed";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
disabled = false,
|
||||
children,
|
||||
child,
|
||||
type,
|
||||
value = $bindable(),
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
onValueChange = noop,
|
||||
loop = true,
|
||||
orientation = "vertical",
|
||||
...restProps
|
||||
}: AccordionRootProps = $props();
|
||||
|
||||
function handleDefaultValue() {
|
||||
if (value !== undefined) return;
|
||||
value = type === "single" ? "" : [];
|
||||
}
|
||||
|
||||
// SSR
|
||||
handleDefaultValue();
|
||||
|
||||
watch.pre(
|
||||
() => value,
|
||||
() => {
|
||||
handleDefaultValue();
|
||||
}
|
||||
);
|
||||
|
||||
const rootState = AccordionRootState.create({
|
||||
type,
|
||||
value: boxWith(
|
||||
() => value!,
|
||||
(v) => {
|
||||
value = v;
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
onValueChange(v as any);
|
||||
}
|
||||
) as WritableBox<string> | WritableBox<string[]>,
|
||||
id: boxWith(() => id),
|
||||
disabled: boxWith(() => disabled),
|
||||
loop: boxWith(() => loop),
|
||||
orientation: boxWith(() => orientation),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, rootState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AccordionRootProps } from "../types.js";
|
||||
declare const Accordion: import("svelte").Component<AccordionRootProps, {}, "value" | "ref">;
|
||||
type Accordion = ReturnType<typeof Accordion>;
|
||||
export default Accordion;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export { default as Root } from "./components/accordion.svelte";
|
||||
export { default as Item } from "./components/accordion-item.svelte";
|
||||
export { default as Header } from "./components/accordion-header.svelte";
|
||||
export { default as Trigger } from "./components/accordion-trigger.svelte";
|
||||
export { default as Content } from "./components/accordion-content.svelte";
|
||||
export type { AccordionRootProps as RootProps, AccordionItemProps as ItemProps, AccordionHeaderProps as HeaderProps, AccordionTriggerProps as TriggerProps, AccordionContentProps as ContentProps, } from "./types.js";
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export { default as Root } from "./components/accordion.svelte";
|
||||
export { default as Item } from "./components/accordion-item.svelte";
|
||||
export { default as Header } from "./components/accordion-header.svelte";
|
||||
export { default as Trigger } from "./components/accordion-trigger.svelte";
|
||||
export { default as Content } from "./components/accordion-content.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Accordion from "./exports.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Accordion from "./exports.js";
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
import type { OnChangeFn, WithChild, WithChildNoChildrenSnippetProps, Without } from "../../internal/types.js";
|
||||
import type { BitsPrimitiveButtonAttributes, BitsPrimitiveDivAttributes } from "../../shared/attributes.js";
|
||||
import type { Orientation } from "../../shared/index.js";
|
||||
export type BaseAccordionRootPropsWithoutHTML = {
|
||||
/**
|
||||
* Whether the accordion is disabled or not.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* Whether to loop through the accordion items when navigating
|
||||
* with the arrow keys.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
loop?: boolean;
|
||||
/**
|
||||
* The orientation of the accordion.
|
||||
*
|
||||
* @default "vertical"
|
||||
*/
|
||||
orientation?: Orientation;
|
||||
};
|
||||
export type AccordionRootSinglePropsWithoutHTML = BaseAccordionRootPropsWithoutHTML & {
|
||||
/**
|
||||
* The type of accordion. If set to `'multiple'`, the accordion will
|
||||
* allow multiple items to be open at the same time. If set to
|
||||
* `'single'`, the accordion will only allow a single item to be open.
|
||||
*
|
||||
* @required
|
||||
*/
|
||||
type: "single";
|
||||
/**
|
||||
* The value of the currently open accordion item.
|
||||
*
|
||||
* @bindable
|
||||
* @default ""
|
||||
*/
|
||||
value?: string;
|
||||
/**
|
||||
* A callback function called when the value changes.
|
||||
*/
|
||||
onValueChange?: OnChangeFn<string>;
|
||||
};
|
||||
export type AccordionRootMultiplePropsWithoutHTML = BaseAccordionRootPropsWithoutHTML & {
|
||||
/**
|
||||
* The type of accordion. If set to `'multiple'`, the accordion will
|
||||
* allow multiple items to be open at the same time. If set to
|
||||
* `'single'`, the accordion will only allow a single item to be open.
|
||||
*
|
||||
* @required
|
||||
*/
|
||||
type: "multiple";
|
||||
/**
|
||||
* The value of the currently open accordion item.
|
||||
*
|
||||
* @bindable
|
||||
* @default []
|
||||
*/
|
||||
value?: string[];
|
||||
/**
|
||||
* A callback function called when the value changes.
|
||||
*/
|
||||
onValueChange?: OnChangeFn<string[]>;
|
||||
};
|
||||
export type AccordionRootPropsWithoutHTML = WithChild<AccordionRootSinglePropsWithoutHTML> | WithChild<AccordionRootMultiplePropsWithoutHTML>;
|
||||
export type AccordionRootProps = AccordionRootPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, AccordionRootPropsWithoutHTML>;
|
||||
export type AccordionRootSingleProps = AccordionRootSinglePropsWithoutHTML & Without<BitsPrimitiveDivAttributes, AccordionRootSinglePropsWithoutHTML>;
|
||||
export type AccordionMultipleProps = AccordionRootMultiplePropsWithoutHTML & Without<BitsPrimitiveDivAttributes, AccordionRootMultiplePropsWithoutHTML>;
|
||||
export type AccordionTriggerPropsWithoutHTML = WithChild;
|
||||
export type AccordionTriggerProps = AccordionTriggerPropsWithoutHTML & Without<BitsPrimitiveButtonAttributes, AccordionTriggerPropsWithoutHTML>;
|
||||
export type AccordionContentSnippetProps = {
|
||||
/**
|
||||
* Whether the accordion content is active/open or not.
|
||||
*/
|
||||
open: boolean;
|
||||
};
|
||||
export type AccordionContentPropsWithoutHTML = WithChildNoChildrenSnippetProps<{
|
||||
/**
|
||||
* Whether to forcefully mount the content, regardless of the open state.
|
||||
* This is useful if you want to use Svelte transitions for the content.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
forceMount?: boolean;
|
||||
/**
|
||||
* Whether to allow the browser to expand the content when searching for content
|
||||
* within the panel via the browser's built-in search functionality.
|
||||
*
|
||||
* When `true`, this prop will override the `forceMount` prop.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
hiddenUntilFound?: boolean;
|
||||
}, AccordionContentSnippetProps>;
|
||||
export type AccordionContentProps = AccordionContentPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, AccordionContentPropsWithoutHTML>;
|
||||
export type AccordionItemPropsWithoutHTML = WithChild<{
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
disabled?: boolean;
|
||||
}>;
|
||||
export type AccordionItemProps = AccordionItemPropsWithoutHTML & BitsPrimitiveDivAttributes;
|
||||
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.
|
||||
*
|
||||
* @default `3`
|
||||
*/
|
||||
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
||||
}>;
|
||||
export type AccordionHeaderProps = AccordionHeaderPropsWithoutHTML & BitsPrimitiveDivAttributes;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AlertDialogActionProps } from "../types.js";
|
||||
import { DialogActionState } from "../../dialog/dialog.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
...restProps
|
||||
}: AlertDialogActionProps = $props();
|
||||
|
||||
const actionState = DialogActionState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, actionState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
declare const AlertDialogAction: import("svelte").Component<import("../types.js").AlertDialogTriggerProps, {}, "ref">;
|
||||
type AlertDialogAction = ReturnType<typeof AlertDialogAction>;
|
||||
export default AlertDialogAction;
|
||||
Generated
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AlertDialogCancelProps } from "../types.js";
|
||||
import { AlertDialogCancelState } from "../../dialog/dialog.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
children,
|
||||
child,
|
||||
disabled = false,
|
||||
...restProps
|
||||
}: AlertDialogCancelProps = $props();
|
||||
|
||||
const cancelState = AlertDialogCancelState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
disabled: boxWith(() => Boolean(disabled)),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, cancelState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
declare const AlertDialogCancel: import("svelte").Component<import("../types.js").AlertDialogTriggerProps, {}, "ref">;
|
||||
type AlertDialogCancel = ReturnType<typeof AlertDialogCancel>;
|
||||
export default AlertDialogCancel;
|
||||
Generated
Vendored
+103
@@ -0,0 +1,103 @@
|
||||
<script lang="ts">
|
||||
import { afterSleep, boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AlertDialogContentProps } from "../types.js";
|
||||
import DismissibleLayer from "../../utilities/dismissible-layer/dismissible-layer.svelte";
|
||||
import EscapeLayer from "../../utilities/escape-layer/escape-layer.svelte";
|
||||
import FocusScope from "../../utilities/focus-scope/focus-scope.svelte";
|
||||
import TextSelectionLayer from "../../utilities/text-selection-layer/text-selection-layer.svelte";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import ScrollLock from "../../utilities/scroll-lock/scroll-lock.svelte";
|
||||
import { DialogContentState } from "../../dialog/dialog.svelte.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
id = createId(uid),
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
forceMount = false,
|
||||
interactOutsideBehavior = "ignore",
|
||||
onCloseAutoFocus = noop,
|
||||
onEscapeKeydown = noop,
|
||||
onOpenAutoFocus = noop,
|
||||
onInteractOutside = noop,
|
||||
preventScroll = true,
|
||||
trapFocus = true,
|
||||
restoreScrollDelay = null,
|
||||
...restProps
|
||||
}: AlertDialogContentProps = $props();
|
||||
|
||||
const contentState = DialogContentState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, contentState.props));
|
||||
</script>
|
||||
|
||||
{#if contentState.shouldRender || forceMount}
|
||||
<FocusScope
|
||||
ref={contentState.opts.ref}
|
||||
loop
|
||||
{trapFocus}
|
||||
enabled={contentState.root.opts.open.current}
|
||||
{onCloseAutoFocus}
|
||||
onOpenAutoFocus={(e) => {
|
||||
onOpenAutoFocus(e);
|
||||
if (e.defaultPrevented) return;
|
||||
e.preventDefault();
|
||||
afterSleep(0, () => contentState.opts.ref.current?.focus());
|
||||
}}
|
||||
>
|
||||
{#snippet focusScope({ props: focusScopeProps })}
|
||||
<EscapeLayer
|
||||
{...mergedProps}
|
||||
enabled={contentState.root.opts.open.current}
|
||||
ref={contentState.opts.ref}
|
||||
onEscapeKeydown={(e) => {
|
||||
onEscapeKeydown(e);
|
||||
if (e.defaultPrevented) return;
|
||||
contentState.root.handleClose();
|
||||
}}
|
||||
>
|
||||
<DismissibleLayer
|
||||
{...mergedProps}
|
||||
ref={contentState.opts.ref}
|
||||
enabled={contentState.root.opts.open.current}
|
||||
{interactOutsideBehavior}
|
||||
onInteractOutside={(e) => {
|
||||
onInteractOutside(e);
|
||||
if (e.defaultPrevented) return;
|
||||
contentState.root.handleClose();
|
||||
}}
|
||||
>
|
||||
<TextSelectionLayer
|
||||
{...mergedProps}
|
||||
ref={contentState.opts.ref}
|
||||
enabled={contentState.root.opts.open.current}
|
||||
>
|
||||
{#if child}
|
||||
{#if contentState.root.opts.open.current}
|
||||
<ScrollLock {preventScroll} {restoreScrollDelay} />
|
||||
{/if}
|
||||
{@render child({
|
||||
props: mergeProps(mergedProps, focusScopeProps),
|
||||
...contentState.snippetProps,
|
||||
})}
|
||||
{:else}
|
||||
<ScrollLock {preventScroll} />
|
||||
<div {...mergeProps(mergedProps, focusScopeProps)}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</TextSelectionLayer>
|
||||
</DismissibleLayer>
|
||||
</EscapeLayer>
|
||||
{/snippet}
|
||||
</FocusScope>
|
||||
{/if}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
declare const AlertDialogContent: import("svelte").Component<import("../../dialog/types.js").DialogContentProps, {}, "ref">;
|
||||
type AlertDialogContent = ReturnType<typeof AlertDialogContent>;
|
||||
export default AlertDialogContent;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { boxWith } from "svelte-toolbelt";
|
||||
import type { AlertDialogRootProps } from "../types.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { DialogRootState } from "../../dialog/dialog.svelte.js";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
onOpenChange = noop,
|
||||
onOpenChangeComplete = noop,
|
||||
children,
|
||||
}: AlertDialogRootProps = $props();
|
||||
|
||||
DialogRootState.create({
|
||||
variant: boxWith(() => "alert-dialog"),
|
||||
open: boxWith(
|
||||
() => open,
|
||||
(v) => {
|
||||
open = v;
|
||||
onOpenChange(v);
|
||||
}
|
||||
),
|
||||
onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
|
||||
});
|
||||
</script>
|
||||
|
||||
{@render children?.()}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
declare const AlertDialog: import("svelte").Component<import("../types.js").AlertDialogRootPropsWithoutHTML, {}, "open">;
|
||||
type AlertDialog = ReturnType<typeof AlertDialog>;
|
||||
export default AlertDialog;
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
export { default as Root } from "./components/alert-dialog.svelte";
|
||||
export { default as Title } from "../dialog/components/dialog-title.svelte";
|
||||
export { default as Action } from "./components/alert-dialog-action.svelte";
|
||||
export { default as Cancel } from "./components/alert-dialog-cancel.svelte";
|
||||
export { default as Portal } from "../utilities/portal/portal.svelte";
|
||||
export { default as Content } from "./components/alert-dialog-content.svelte";
|
||||
export { default as Overlay } from "../dialog/components/dialog-overlay.svelte";
|
||||
export { default as Trigger } from "../dialog/components/dialog-trigger.svelte";
|
||||
export { default as Description } from "../dialog/components/dialog-description.svelte";
|
||||
export type { AlertDialogRootProps as RootProps, AlertDialogTitleProps as TitleProps, AlertDialogActionProps as ActionProps, AlertDialogCancelProps as CancelProps, AlertDialogPortalProps as PortalProps, AlertDialogContentProps as ContentProps, AlertDialogOverlayProps as OverlayProps, AlertDialogTriggerProps as TriggerProps, AlertDialogDescriptionProps as DescriptionProps, } from "./types.js";
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
export { default as Root } from "./components/alert-dialog.svelte";
|
||||
export { default as Title } from "../dialog/components/dialog-title.svelte";
|
||||
export { default as Action } from "./components/alert-dialog-action.svelte";
|
||||
export { default as Cancel } from "./components/alert-dialog-cancel.svelte";
|
||||
export { default as Portal } from "../utilities/portal/portal.svelte";
|
||||
export { default as Content } from "./components/alert-dialog-content.svelte";
|
||||
export { default as Overlay } from "../dialog/components/dialog-overlay.svelte";
|
||||
export { default as Trigger } from "../dialog/components/dialog-trigger.svelte";
|
||||
export { default as Description } from "../dialog/components/dialog-description.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as AlertDialog from "./exports.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as AlertDialog from "./exports.js";
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { DialogContentProps, DialogContentPropsWithoutHTML } from "../../types.js";
|
||||
export type { DialogRootPropsWithoutHTML as AlertDialogRootPropsWithoutHTML, DialogRootProps as AlertDialogRootProps, DialogClosePropsWithoutHTML as AlertDialogActionPropsWithoutHTML, DialogCloseProps as AlertDialogActionProps, DialogClosePropsWithoutHTML as AlertDialogCancelPropsWithoutHTML, DialogCloseProps as AlertDialogCancelProps, DialogPortalPropsWithoutHTML as AlertDialogPortalPropsWithoutHTML, DialogPortalProps as AlertDialogPortalProps, DialogOverlayPropsWithoutHTML as AlertDialogOverlayPropsWithoutHTML, DialogOverlayProps as AlertDialogOverlayProps, DialogTitlePropsWithoutHTML as AlertDialogTitlePropsWithoutHTML, DialogTitleProps as AlertDialogTitleProps, DialogDescriptionPropsWithoutHTML as AlertDialogDescriptionPropsWithoutHTML, DialogDescriptionProps as AlertDialogDescriptionProps, DialogTriggerPropsWithoutHTML as AlertDialogTriggerPropsWithoutHTML, DialogTriggerProps as AlertDialogTriggerProps, } from "../dialog/types.js";
|
||||
export type AlertDialogContentPropsWithoutHTML = Omit<DialogContentPropsWithoutHTML, "onInteractOutside">;
|
||||
export type AlertDialogContentProps = DialogContentProps;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { type ReadableBoxedValues } from "svelte-toolbelt";
|
||||
import type { RefAttachment, WithRefOpts } from "../../internal/types.js";
|
||||
interface AspectRatioRootStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
ratio: number;
|
||||
}> {
|
||||
}
|
||||
export declare class AspectRatioRootState {
|
||||
static create(opts: AspectRatioRootStateOpts): AspectRatioRootState;
|
||||
readonly opts: AspectRatioRootStateOpts;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AspectRatioRootStateOpts);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly style: {
|
||||
readonly position: "absolute";
|
||||
readonly top: 0;
|
||||
readonly right: 0;
|
||||
readonly bottom: 0;
|
||||
readonly left: 0;
|
||||
};
|
||||
};
|
||||
}
|
||||
export {};
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { attachRef } from "svelte-toolbelt";
|
||||
import { createBitsAttrs } from "../../internal/attrs.js";
|
||||
const aspectRatioAttrs = createBitsAttrs({
|
||||
component: "aspect-ratio",
|
||||
parts: ["root"],
|
||||
});
|
||||
export class AspectRatioRootState {
|
||||
static create(opts) {
|
||||
return new AspectRatioRootState(opts);
|
||||
}
|
||||
opts;
|
||||
attachment;
|
||||
constructor(opts) {
|
||||
this.opts = opts;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
style: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
[aspectRatioAttrs.root]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AspectRatioRootProps } from "../types.js";
|
||||
import { AspectRatioRootState } from "../aspect-ratio.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
ratio = 1,
|
||||
children,
|
||||
child,
|
||||
...restProps
|
||||
}: AspectRatioRootProps = $props();
|
||||
|
||||
const rootState = AspectRatioRootState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
ratio: boxWith(() => ratio),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, rootState.props));
|
||||
</script>
|
||||
|
||||
<div style:position="relative" style:width="100%" style:padding-bottom="{ratio ? 100 / ratio : 0}%">
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AspectRatioRootProps } from "../types.js";
|
||||
declare const AspectRatio: import("svelte").Component<AspectRatioRootProps, {}, "ref">;
|
||||
type AspectRatio = ReturnType<typeof AspectRatio>;
|
||||
export default AspectRatio;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export { default as Root } from "./components/aspect-ratio.svelte";
|
||||
export type { AspectRatioRootProps as RootProps } from "./types.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { default as Root } from "./components/aspect-ratio.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as AspectRatio from "./exports.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as AspectRatio from "./exports.js";
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { WithChild, Without } from "../../internal/types.js";
|
||||
import type { BitsPrimitiveDivAttributes } from "../../shared/attributes.js";
|
||||
export type AspectRatioRootPropsWithoutHTML = WithChild<{
|
||||
/**
|
||||
* The aspect ratio of the image.
|
||||
*
|
||||
* @defaultValue 1
|
||||
*/
|
||||
ratio?: number;
|
||||
}>;
|
||||
export type AspectRatioRootProps = AspectRatioRootPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, AspectRatioRootPropsWithoutHTML>;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { DOMContext, type ReadableBox, type WritableBox, type ReadableBoxedValues } from "svelte-toolbelt";
|
||||
import type { HTMLImgAttributes } from "svelte/elements";
|
||||
import type { AvatarImageLoadingStatus } from "./types.js";
|
||||
import type { RefAttachment, WithRefOpts } from "../../internal/types.js";
|
||||
type CrossOrigin = HTMLImgAttributes["crossorigin"];
|
||||
type ReferrerPolicy = HTMLImgAttributes["referrerpolicy"];
|
||||
type AvatarImageSrc = string | null | undefined;
|
||||
interface AvatarRootStateOpts extends WithRefOpts {
|
||||
delayMs: ReadableBox<number>;
|
||||
loadingStatus: WritableBox<AvatarImageLoadingStatus>;
|
||||
}
|
||||
export declare class AvatarRootState {
|
||||
static create(opts: AvatarRootStateOpts): AvatarRootState;
|
||||
readonly opts: AvatarRootStateOpts;
|
||||
readonly domContext: DOMContext;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AvatarRootStateOpts);
|
||||
loadImage(src: string, crossorigin?: CrossOrigin, referrerPolicy?: ReferrerPolicy): (() => void) | undefined;
|
||||
props: {
|
||||
readonly id: string;
|
||||
readonly "data-status": AvatarImageLoadingStatus;
|
||||
};
|
||||
}
|
||||
interface AvatarImageStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
src: AvatarImageSrc;
|
||||
crossOrigin: CrossOrigin;
|
||||
referrerPolicy: ReferrerPolicy;
|
||||
}> {
|
||||
}
|
||||
export declare class AvatarImageState {
|
||||
static create(opts: AvatarImageStateOpts): AvatarImageState;
|
||||
readonly opts: AvatarImageStateOpts;
|
||||
readonly root: AvatarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AvatarImageStateOpts, root: AvatarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly style: {
|
||||
readonly display: "none" | "block";
|
||||
};
|
||||
readonly "data-status": AvatarImageLoadingStatus;
|
||||
readonly src: AvatarImageSrc;
|
||||
readonly crossorigin: "" | "anonymous" | "use-credentials" | null | undefined;
|
||||
readonly referrerpolicy: globalThis.ReferrerPolicy | null | undefined;
|
||||
};
|
||||
}
|
||||
interface AvatarFallbackStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class AvatarFallbackState {
|
||||
static create(opts: AvatarFallbackStateOpts): AvatarFallbackState;
|
||||
readonly opts: AvatarFallbackStateOpts;
|
||||
readonly root: AvatarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: AvatarFallbackStateOpts, root: AvatarRootState);
|
||||
readonly style: {
|
||||
display: string;
|
||||
} | undefined;
|
||||
readonly props: {
|
||||
readonly style: {
|
||||
display: string;
|
||||
} | undefined;
|
||||
readonly "data-status": AvatarImageLoadingStatus;
|
||||
};
|
||||
}
|
||||
export {};
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import { DOMContext, attachRef, } from "svelte-toolbelt";
|
||||
import { Context, watch } from "runed";
|
||||
import { createBitsAttrs } from "../../internal/attrs.js";
|
||||
const avatarAttrs = createBitsAttrs({
|
||||
component: "avatar",
|
||||
parts: ["root", "image", "fallback"],
|
||||
});
|
||||
const AvatarRootContext = new Context("Avatar.Root");
|
||||
export class AvatarRootState {
|
||||
static create(opts) {
|
||||
return AvatarRootContext.set(new AvatarRootState(opts));
|
||||
}
|
||||
opts;
|
||||
domContext;
|
||||
attachment;
|
||||
constructor(opts) {
|
||||
this.opts = opts;
|
||||
this.domContext = new DOMContext(this.opts.ref);
|
||||
this.loadImage = this.loadImage.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
loadImage(src, crossorigin, referrerPolicy) {
|
||||
if (this.opts.loadingStatus.current === "loaded")
|
||||
return;
|
||||
let imageTimerId;
|
||||
const image = new Image();
|
||||
image.src = src;
|
||||
if (crossorigin !== undefined)
|
||||
image.crossOrigin = crossorigin;
|
||||
if (referrerPolicy)
|
||||
image.referrerPolicy = referrerPolicy;
|
||||
this.opts.loadingStatus.current = "loading";
|
||||
image.onload = () => {
|
||||
imageTimerId = this.domContext.setTimeout(() => {
|
||||
this.opts.loadingStatus.current = "loaded";
|
||||
}, this.opts.delayMs.current);
|
||||
};
|
||||
image.onerror = () => {
|
||||
this.opts.loadingStatus.current = "error";
|
||||
};
|
||||
return () => {
|
||||
if (!imageTimerId)
|
||||
return;
|
||||
this.domContext.clearTimeout(imageTimerId);
|
||||
};
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
[avatarAttrs.root]: "",
|
||||
"data-status": this.opts.loadingStatus.current,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class AvatarImageState {
|
||||
static create(opts) {
|
||||
return new AvatarImageState(opts, AvatarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
watch.pre([() => this.opts.src.current, () => this.opts.crossOrigin.current], ([src, crossOrigin]) => {
|
||||
if (!src) {
|
||||
this.root.opts.loadingStatus.current = "error";
|
||||
return;
|
||||
}
|
||||
this.root.loadImage(src, crossOrigin, this.opts.referrerPolicy.current);
|
||||
});
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
style: {
|
||||
display: this.root.opts.loadingStatus.current === "loaded" ? "block" : "none",
|
||||
},
|
||||
"data-status": this.root.opts.loadingStatus.current,
|
||||
[avatarAttrs.image]: "",
|
||||
src: this.opts.src.current,
|
||||
crossorigin: this.opts.crossOrigin.current,
|
||||
referrerpolicy: this.opts.referrerPolicy.current,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class AvatarFallbackState {
|
||||
static create(opts) {
|
||||
return new AvatarFallbackState(opts, AvatarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
style = $derived.by(() => this.root.opts.loadingStatus.current === "loaded" ? { display: "none" } : undefined);
|
||||
props = $derived.by(() => ({
|
||||
style: this.style,
|
||||
"data-status": this.root.opts.loadingStatus.current,
|
||||
[avatarAttrs.fallback]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AvatarFallbackProps } from "../types.js";
|
||||
import { AvatarFallbackState } from "../avatar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
...restProps
|
||||
}: AvatarFallbackProps = $props();
|
||||
|
||||
const fallbackState = AvatarFallbackState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, fallbackState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<span {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</span>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AvatarFallbackProps } from "../types.js";
|
||||
declare const AvatarFallback: import("svelte").Component<AvatarFallbackProps, {}, "ref">;
|
||||
type AvatarFallback = ReturnType<typeof AvatarFallback>;
|
||||
export default AvatarFallback;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AvatarImageProps } from "../types.js";
|
||||
import { AvatarImageState } from "../avatar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
src,
|
||||
child,
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
crossorigin = undefined,
|
||||
referrerpolicy = undefined,
|
||||
...restProps
|
||||
}: AvatarImageProps = $props();
|
||||
|
||||
const imageState = AvatarImageState.create({
|
||||
src: boxWith(() => src),
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
crossOrigin: boxWith(() => crossorigin),
|
||||
referrerPolicy: boxWith(() => referrerpolicy),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, imageState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<img {...mergedProps} {src} />
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AvatarImageProps } from "../types.js";
|
||||
declare const AvatarImage: import("svelte").Component<AvatarImageProps, {}, "ref">;
|
||||
type AvatarImage = ReturnType<typeof AvatarImage>;
|
||||
export default AvatarImage;
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { AvatarRootProps } from "../types.js";
|
||||
import { AvatarRootState } from "../avatar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
delayMs = 0,
|
||||
loadingStatus = $bindable("loading"),
|
||||
onLoadingStatusChange,
|
||||
child,
|
||||
children,
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
...restProps
|
||||
}: AvatarRootProps = $props();
|
||||
|
||||
const rootState = AvatarRootState.create({
|
||||
delayMs: boxWith(() => delayMs),
|
||||
loadingStatus: boxWith(
|
||||
() => loadingStatus,
|
||||
(v) => {
|
||||
if (loadingStatus !== v) {
|
||||
loadingStatus = v;
|
||||
onLoadingStatusChange?.(v);
|
||||
}
|
||||
}
|
||||
),
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, rootState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { AvatarRootProps } from "../types.js";
|
||||
declare const Avatar: import("svelte").Component<AvatarRootProps, {}, "ref" | "loadingStatus">;
|
||||
type Avatar = ReturnType<typeof Avatar>;
|
||||
export default Avatar;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export { default as Root } from "./components/avatar.svelte";
|
||||
export { default as Image } from "./components/avatar-image.svelte";
|
||||
export { default as Fallback } from "./components/avatar-fallback.svelte";
|
||||
export type { AvatarRootProps as RootProps, AvatarImageProps as ImageProps, AvatarFallbackProps as FallbackProps, } from "./types.js";
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export { default as Root } from "./components/avatar.svelte";
|
||||
export { default as Image } from "./components/avatar-image.svelte";
|
||||
export { default as Fallback } from "./components/avatar-fallback.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Avatar from "./exports.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Avatar from "./exports.js";
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import type { OnChangeFn, WithChild, Without } from "../../internal/types.js";
|
||||
import type { BitsPrimitiveDivAttributes, BitsPrimitiveImgAttributes, BitsPrimitiveSpanAttributes } from "../../shared/attributes.js";
|
||||
export type AvatarImageLoadingStatus = "loading" | "loaded" | "error";
|
||||
export type AvatarRootPropsWithoutHTML = WithChild<{
|
||||
/**
|
||||
* The delay in milliseconds to wait before showing the avatar once
|
||||
* the image has loaded. This can be used to prevent sudden flickering
|
||||
* of the image if it loads quickly.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
delayMs?: number;
|
||||
/**
|
||||
* The loading status of the image.
|
||||
*
|
||||
* If you are confident that the image exists and will load successfully, you can
|
||||
* set this to `"loaded"` to skip the loading process (which shows the fallback)
|
||||
* and immediately show the image.
|
||||
*
|
||||
* @default "loading"
|
||||
*/
|
||||
loadingStatus?: AvatarImageLoadingStatus;
|
||||
/**
|
||||
* A callback invoked when the loading status of the image changes.
|
||||
*/
|
||||
onLoadingStatusChange?: OnChangeFn<AvatarImageLoadingStatus>;
|
||||
}>;
|
||||
export type AvatarRootProps = AvatarRootPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, AvatarRootPropsWithoutHTML>;
|
||||
export type AvatarImagePropsWithoutHTML = WithChild;
|
||||
export type AvatarImageProps = AvatarImagePropsWithoutHTML & Without<BitsPrimitiveImgAttributes, AvatarImagePropsWithoutHTML>;
|
||||
export type AvatarFallbackPropsWithoutHTML = WithChild;
|
||||
export type AvatarFallbackProps = AvatarFallbackPropsWithoutHTML & Without<BitsPrimitiveSpanAttributes, AvatarFallbackPropsWithoutHTML>;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import type { ButtonRootProps } from "../types.js";
|
||||
|
||||
let {
|
||||
href,
|
||||
type,
|
||||
children,
|
||||
disabled = false,
|
||||
ref = $bindable(null),
|
||||
...restProps
|
||||
}: ButtonRootProps = $props();
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={href ? "a" : "button"}
|
||||
data-button-root
|
||||
type={href ? undefined : type}
|
||||
href={href && !disabled ? href : undefined}
|
||||
disabled={href ? undefined : disabled}
|
||||
aria-disabled={href ? disabled : undefined}
|
||||
role={href && disabled ? "link" : undefined}
|
||||
tabindex={href && disabled ? -1 : 0}
|
||||
bind:this={ref}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
</svelte:element>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { ButtonRootProps } from "../types.js";
|
||||
declare const Button: import("svelte").Component<ButtonRootProps, {}, "ref">;
|
||||
type Button = ReturnType<typeof Button>;
|
||||
export default Button;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export { default as Root } from "./components/button.svelte";
|
||||
export type { ButtonRootProps as RootProps } from "./types.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { default as Root } from "./components/button.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Button from "./exports.js";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Button from "./exports.js";
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
|
||||
import type { WithoutChildren } from "svelte-toolbelt";
|
||||
import type { WithChildren } from "../../shared/index.js";
|
||||
export type ButtonRootPropsWithoutHTML = WithChildren<{
|
||||
ref?: HTMLElement | null;
|
||||
}>;
|
||||
type AnchorElement = ButtonRootPropsWithoutHTML & WithoutChildren<Omit<HTMLAnchorAttributes, "href" | "type">> & {
|
||||
href: HTMLAnchorAttributes["href"];
|
||||
type?: never;
|
||||
disabled?: HTMLButtonAttributes["disabled"];
|
||||
};
|
||||
type ButtonElement = ButtonRootPropsWithoutHTML & WithoutChildren<Omit<HTMLButtonAttributes, "type" | "href">> & {
|
||||
type?: HTMLButtonAttributes["type"];
|
||||
href?: never;
|
||||
disabled?: HTMLButtonAttributes["disabled"];
|
||||
};
|
||||
export type ButtonRootProps = AnchorElement | ButtonElement;
|
||||
export {};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+416
@@ -0,0 +1,416 @@
|
||||
import { type DateValue } from "@internationalized/date";
|
||||
import { DOMContext, type ReadableBoxedValues, type WritableBoxedValues } from "svelte-toolbelt";
|
||||
import { Context } from "runed";
|
||||
import type { RangeCalendarRootState } from "../range-calendar/range-calendar.svelte.js";
|
||||
import type { BitsKeyboardEvent, BitsMouseEvent, RefAttachment, WithRefOpts } from "../../internal/types.js";
|
||||
import type { DateMatcher, Month } from "../../shared/index.js";
|
||||
import { type Announcer } from "../../internal/date-time/announcer.js";
|
||||
import { type Formatter } from "../../internal/date-time/formatter.js";
|
||||
import { calendarAttrs } from "../../internal/date-time/calendar-helpers.svelte.js";
|
||||
import type { WeekStartsOn } from "../../shared/date/types.js";
|
||||
interface CalendarRootStateOpts extends WithRefOpts, WritableBoxedValues<{
|
||||
value: DateValue | undefined | DateValue[];
|
||||
placeholder: DateValue;
|
||||
}>, ReadableBoxedValues<{
|
||||
preventDeselect: boolean;
|
||||
minValue: DateValue | undefined;
|
||||
maxValue: DateValue | undefined;
|
||||
disabled: boolean;
|
||||
pagedNavigation: boolean;
|
||||
weekStartsOn: WeekStartsOn | undefined;
|
||||
weekdayFormat: Intl.DateTimeFormatOptions["weekday"];
|
||||
isDateDisabled: DateMatcher;
|
||||
isDateUnavailable: DateMatcher;
|
||||
fixedWeeks: boolean;
|
||||
numberOfMonths: number;
|
||||
locale: string;
|
||||
calendarLabel: string;
|
||||
type: "single" | "multiple";
|
||||
readonly: boolean;
|
||||
disableDaysOutsideMonth: boolean;
|
||||
initialFocus: boolean;
|
||||
maxDays: number | undefined;
|
||||
/**
|
||||
* This is strictly used by the `DatePicker` component to close the popover when a date
|
||||
* is selected. It is not intended to be used by the user.
|
||||
*/
|
||||
onDateSelect?: () => void;
|
||||
monthFormat: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
|
||||
yearFormat: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
|
||||
}> {
|
||||
defaultPlaceholder: DateValue;
|
||||
}
|
||||
export declare const CalendarRootContext: Context<RangeCalendarRootState | CalendarRootState>;
|
||||
export declare class CalendarRootState {
|
||||
#private;
|
||||
static create(opts: CalendarRootStateOpts): RangeCalendarRootState | CalendarRootState;
|
||||
readonly opts: CalendarRootStateOpts;
|
||||
readonly visibleMonths: DateValue[];
|
||||
readonly formatter: Formatter;
|
||||
readonly accessibleHeadingId: string;
|
||||
readonly domContext: DOMContext;
|
||||
readonly attachment: RefAttachment;
|
||||
months: Month<DateValue>[];
|
||||
announcer: Announcer;
|
||||
constructor(opts: CalendarRootStateOpts);
|
||||
setMonths(months: Month<DateValue>[]): void;
|
||||
/**
|
||||
* This derived state holds an array of localized day names for the current
|
||||
* locale and calendar view. It dynamically syncs with the 'weekStartsOn' option,
|
||||
* updating its content when the option changes. Using this state to render the
|
||||
* calendar's days of the week is strongly recommended, as it guarantees that
|
||||
* the days are correctly formatted for the current locale and calendar view.
|
||||
*/
|
||||
readonly weekdays: string[];
|
||||
readonly initialPlaceholderYear: number;
|
||||
readonly defaultYears: number[];
|
||||
/**
|
||||
* Navigates to the next page of the calendar.
|
||||
*/
|
||||
nextPage(): void;
|
||||
/**
|
||||
* Navigates to the previous page of the calendar.
|
||||
*/
|
||||
prevPage(): void;
|
||||
nextYear(): void;
|
||||
prevYear(): void;
|
||||
setYear(year: number): void;
|
||||
setMonth(month: number): void;
|
||||
isNextButtonDisabled: boolean;
|
||||
isPrevButtonDisabled: boolean;
|
||||
isInvalid: boolean;
|
||||
readonly headingValue: string;
|
||||
readonly fullCalendarLabel: string;
|
||||
isOutsideVisibleMonths(date: DateValue): boolean;
|
||||
isDateDisabled(date: DateValue): boolean;
|
||||
isDateSelected(date: DateValue): boolean;
|
||||
shiftFocus(node: HTMLElement, add: number): void;
|
||||
handleCellClick(_: Event, date: DateValue): void;
|
||||
handleMultipleUpdate(prev: DateValue[] | undefined, date: DateValue): DateValue[] | undefined;
|
||||
handleSingleUpdate(prev: DateValue | undefined, date: DateValue): DateValue | undefined;
|
||||
onkeydown(event: BitsKeyboardEvent): void;
|
||||
readonly snippetProps: {
|
||||
months: Month<DateValue>[];
|
||||
weekdays: string[];
|
||||
};
|
||||
getBitsAttr: (typeof calendarAttrs)["getAttr"];
|
||||
readonly props: {
|
||||
readonly onkeydown: (event: BitsKeyboardEvent) => void;
|
||||
readonly id: string;
|
||||
readonly role: "application";
|
||||
readonly "aria-label": string;
|
||||
readonly "data-invalid": "" | undefined;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarHeadingStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarHeadingState {
|
||||
static create(opts: CalendarHeadingStateOpts): CalendarHeadingState;
|
||||
readonly opts: CalendarHeadingStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarHeadingStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "aria-hidden": "true" | undefined;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarCellStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
date: DateValue;
|
||||
month: DateValue;
|
||||
}> {
|
||||
}
|
||||
export declare class CalendarCellState {
|
||||
static create(opts: CalendarCellStateOpts): CalendarCellState;
|
||||
readonly opts: CalendarCellStateOpts;
|
||||
readonly root: CalendarRootState;
|
||||
readonly cellDate: Date;
|
||||
readonly isUnavailable: boolean;
|
||||
readonly isDateToday: boolean;
|
||||
readonly isOutsideMonth: boolean;
|
||||
readonly isOutsideVisibleMonths: boolean;
|
||||
readonly isDisabled: boolean;
|
||||
readonly isFocusedDate: boolean;
|
||||
readonly isSelectedDate: boolean;
|
||||
readonly labelText: string;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarCellStateOpts, root: CalendarRootState);
|
||||
readonly snippetProps: {
|
||||
disabled: boolean;
|
||||
unavailable: boolean;
|
||||
selected: boolean;
|
||||
day: string;
|
||||
};
|
||||
readonly ariaDisabled: boolean;
|
||||
readonly sharedDataAttrs: {
|
||||
readonly "data-unavailable": "" | undefined;
|
||||
readonly "data-today": "" | undefined;
|
||||
readonly "data-outside-month": "" | undefined;
|
||||
readonly "data-outside-visible-months": "" | undefined;
|
||||
readonly "data-focused": "" | undefined;
|
||||
readonly "data-selected": "" | undefined;
|
||||
readonly "data-value": string;
|
||||
readonly "data-type": string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
};
|
||||
readonly props: {
|
||||
readonly "data-unavailable": "" | undefined;
|
||||
readonly "data-today": "" | undefined;
|
||||
readonly "data-outside-month": "" | undefined;
|
||||
readonly "data-outside-visible-months": "" | undefined;
|
||||
readonly "data-focused": "" | undefined;
|
||||
readonly "data-selected": "" | undefined;
|
||||
readonly "data-value": string;
|
||||
readonly "data-type": string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly id: string;
|
||||
readonly role: "gridcell";
|
||||
readonly "aria-selected": "true" | "false";
|
||||
readonly "aria-disabled": "true" | "false";
|
||||
};
|
||||
}
|
||||
interface CalendarDayStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarDayState {
|
||||
#private;
|
||||
static create(opts: CalendarDayStateOpts): CalendarDayState;
|
||||
readonly opts: CalendarDayStateOpts;
|
||||
readonly cell: CalendarCellState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarDayStateOpts, cell: CalendarCellState);
|
||||
onclick(e: BitsMouseEvent): void;
|
||||
readonly snippetProps: {
|
||||
disabled: boolean;
|
||||
unavailable: boolean;
|
||||
selected: boolean;
|
||||
day: string;
|
||||
};
|
||||
readonly props: {
|
||||
readonly tabindex: 0 | -1 | undefined;
|
||||
readonly "data-bits-day": "";
|
||||
readonly onclick: (e: BitsMouseEvent) => void;
|
||||
readonly "data-unavailable": "" | undefined;
|
||||
readonly "data-today": "" | undefined;
|
||||
readonly "data-outside-month": "" | undefined;
|
||||
readonly "data-outside-visible-months": "" | undefined;
|
||||
readonly "data-focused": "" | undefined;
|
||||
readonly "data-selected": "" | undefined;
|
||||
readonly "data-value": string;
|
||||
readonly "data-type": string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly id: string;
|
||||
readonly role: "button";
|
||||
readonly "aria-label": string;
|
||||
readonly "aria-disabled": "true" | "false";
|
||||
};
|
||||
}
|
||||
interface CalendarNextButtonStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarNextButtonState {
|
||||
static create(opts: CalendarNextButtonStateOpts): CalendarNextButtonState;
|
||||
readonly opts: CalendarNextButtonStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly isDisabled: boolean;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarNextButtonStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
onclick(_: BitsMouseEvent): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly role: "button";
|
||||
readonly type: "button";
|
||||
readonly "aria-label": "Next";
|
||||
readonly "aria-disabled": "true" | "false";
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly disabled: boolean;
|
||||
readonly onclick: (_: BitsMouseEvent) => void;
|
||||
};
|
||||
}
|
||||
interface CalendarPrevButtonStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarPrevButtonState {
|
||||
static create(opts: CalendarPrevButtonStateOpts): CalendarPrevButtonState;
|
||||
readonly opts: CalendarPrevButtonStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly isDisabled: boolean;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarPrevButtonStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
onclick(_: BitsMouseEvent): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly role: "button";
|
||||
readonly type: "button";
|
||||
readonly "aria-label": "Previous";
|
||||
readonly "aria-disabled": "true" | "false";
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly disabled: boolean;
|
||||
readonly onclick: (_: BitsMouseEvent) => void;
|
||||
};
|
||||
}
|
||||
interface CalendarGridStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarGridState {
|
||||
static create(opts: CalendarGridStateOpts): CalendarGridState;
|
||||
readonly opts: CalendarGridStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarGridStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly tabindex: -1;
|
||||
readonly role: "grid";
|
||||
readonly "aria-readonly": "true" | "false";
|
||||
readonly "aria-disabled": "true" | "false";
|
||||
readonly "data-readonly": "" | undefined;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarGridBodyStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarGridBodyState {
|
||||
static create(opts: CalendarGridBodyStateOpts): CalendarGridBodyState;
|
||||
readonly opts: CalendarGridBodyStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarGridBodyStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarGridHeadStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarGridHeadState {
|
||||
static create(opts: CalendarGridHeadStateOpts): CalendarGridHeadState;
|
||||
readonly opts: CalendarGridHeadStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarGridHeadStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarGridRowStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarGridRowState {
|
||||
static create(opts: CalendarGridRowStateOpts): CalendarGridRowState;
|
||||
readonly opts: CalendarGridRowStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarGridRowStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarHeadCellStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarHeadCellState {
|
||||
static create(opts: CalendarHeadCellStateOpts): CalendarHeadCellState;
|
||||
readonly opts: CalendarHeadCellStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarHeadCellStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarHeaderStateOpts extends WithRefOpts {
|
||||
}
|
||||
export declare class CalendarHeaderState {
|
||||
static create(opts: CalendarHeaderStateOpts): CalendarHeaderState;
|
||||
readonly opts: CalendarHeaderStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarHeaderStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly "data-readonly": "" | undefined;
|
||||
};
|
||||
}
|
||||
interface CalendarMonthSelectStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
months: number[];
|
||||
monthFormat: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
|
||||
disabled: boolean;
|
||||
}> {
|
||||
}
|
||||
export declare class CalendarMonthSelectState {
|
||||
static create(opts: CalendarMonthSelectStateOpts): CalendarMonthSelectState;
|
||||
readonly opts: CalendarMonthSelectStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarMonthSelectStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly monthItems: {
|
||||
value: number;
|
||||
label: string;
|
||||
}[];
|
||||
readonly currentMonth: number;
|
||||
readonly isDisabled: boolean;
|
||||
readonly snippetProps: {
|
||||
monthItems: {
|
||||
value: number;
|
||||
label: string;
|
||||
}[];
|
||||
selectedMonthItem: {
|
||||
value: number;
|
||||
label: string;
|
||||
};
|
||||
};
|
||||
onchange(event: Event): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly value: number;
|
||||
readonly disabled: boolean;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly onchange: (event: Event) => void;
|
||||
};
|
||||
}
|
||||
interface CalendarYearSelectStateOpts extends WithRefOpts, ReadableBoxedValues<{
|
||||
years: number[] | undefined;
|
||||
yearFormat: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
|
||||
disabled: boolean;
|
||||
}> {
|
||||
}
|
||||
export declare class CalendarYearSelectState {
|
||||
static create(opts: CalendarYearSelectStateOpts): CalendarYearSelectState;
|
||||
readonly opts: CalendarYearSelectStateOpts;
|
||||
readonly root: CalendarRootState | RangeCalendarRootState;
|
||||
readonly attachment: RefAttachment;
|
||||
constructor(opts: CalendarYearSelectStateOpts, root: CalendarRootState | RangeCalendarRootState);
|
||||
readonly years: number[];
|
||||
readonly yearItems: {
|
||||
value: number;
|
||||
label: string;
|
||||
}[];
|
||||
readonly currentYear: number;
|
||||
readonly isDisabled: boolean;
|
||||
readonly snippetProps: {
|
||||
yearItems: {
|
||||
value: number;
|
||||
label: string;
|
||||
}[];
|
||||
selectedYearItem: {
|
||||
value: number;
|
||||
label: string;
|
||||
};
|
||||
};
|
||||
onchange(event: Event): void;
|
||||
readonly props: {
|
||||
readonly id: string;
|
||||
readonly value: number;
|
||||
readonly disabled: boolean;
|
||||
readonly "data-disabled": "" | undefined;
|
||||
readonly onchange: (event: Event) => void;
|
||||
};
|
||||
}
|
||||
export {};
|
||||
+870
@@ -0,0 +1,870 @@
|
||||
import { getLocalTimeZone, isSameDay, isSameMonth, isToday, } from "@internationalized/date";
|
||||
import { DEV } from "esm-env";
|
||||
import { onMount, untrack } from "svelte";
|
||||
import { attachRef, DOMContext, } from "svelte-toolbelt";
|
||||
import { Context, watch } from "runed";
|
||||
import { boolToStr, boolToStrTrueOrUndef, boolToEmptyStrOrUndef } from "../../internal/attrs.js";
|
||||
import { useId } from "../../internal/use-id.js";
|
||||
import { getAnnouncer } from "../../internal/date-time/announcer.js";
|
||||
import { createFormatter } from "../../internal/date-time/formatter.js";
|
||||
import { calendarAttrs, createAccessibleHeading, createMonths, getCalendarElementProps, getCalendarHeadingValue, getDateWithPreviousTime, getDefaultYears, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
|
||||
import { getDateValueType, isBefore, toDate } from "../../internal/date-time/utils.js";
|
||||
export const CalendarRootContext = new Context("Calendar.Root | RangeCalender.Root");
|
||||
export class CalendarRootState {
|
||||
static create(opts) {
|
||||
return CalendarRootContext.set(new CalendarRootState(opts));
|
||||
}
|
||||
opts;
|
||||
visibleMonths = $derived.by(() => this.months.map((month) => month.value));
|
||||
formatter;
|
||||
accessibleHeadingId = useId();
|
||||
domContext;
|
||||
attachment;
|
||||
months = $state([]);
|
||||
announcer;
|
||||
constructor(opts) {
|
||||
this.opts = opts;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
this.domContext = new DOMContext(opts.ref);
|
||||
this.announcer = getAnnouncer(null);
|
||||
this.formatter = createFormatter({
|
||||
initialLocale: this.opts.locale.current,
|
||||
monthFormat: this.opts.monthFormat,
|
||||
yearFormat: this.opts.yearFormat,
|
||||
});
|
||||
this.setMonths = this.setMonths.bind(this);
|
||||
this.nextPage = this.nextPage.bind(this);
|
||||
this.prevPage = this.prevPage.bind(this);
|
||||
this.prevYear = this.prevYear.bind(this);
|
||||
this.nextYear = this.nextYear.bind(this);
|
||||
this.setYear = this.setYear.bind(this);
|
||||
this.setMonth = this.setMonth.bind(this);
|
||||
this.isOutsideVisibleMonths = this.isOutsideVisibleMonths.bind(this);
|
||||
this.isDateDisabled = this.isDateDisabled.bind(this);
|
||||
this.isDateSelected = this.isDateSelected.bind(this);
|
||||
this.shiftFocus = this.shiftFocus.bind(this);
|
||||
this.handleCellClick = this.handleCellClick.bind(this);
|
||||
this.handleMultipleUpdate = this.handleMultipleUpdate.bind(this);
|
||||
this.handleSingleUpdate = this.handleSingleUpdate.bind(this);
|
||||
this.onkeydown = this.onkeydown.bind(this);
|
||||
this.getBitsAttr = this.getBitsAttr.bind(this);
|
||||
onMount(() => {
|
||||
this.announcer = getAnnouncer(this.domContext.getDocument());
|
||||
});
|
||||
this.months = createMonths({
|
||||
dateObj: this.opts.placeholder.current,
|
||||
weekStartsOn: this.opts.weekStartsOn.current,
|
||||
locale: this.opts.locale.current,
|
||||
fixedWeeks: this.opts.fixedWeeks.current,
|
||||
numberOfMonths: this.opts.numberOfMonths.current,
|
||||
});
|
||||
this.#setupInitialFocusEffect();
|
||||
this.#setupAccessibleHeadingEffect();
|
||||
this.#setupFormatterEffect();
|
||||
/**
|
||||
* Updates the displayed months based on changes in the placeholder value.
|
||||
*/
|
||||
useMonthViewPlaceholderSync({
|
||||
placeholder: this.opts.placeholder,
|
||||
getVisibleMonths: () => this.visibleMonths,
|
||||
weekStartsOn: this.opts.weekStartsOn,
|
||||
locale: this.opts.locale,
|
||||
fixedWeeks: this.opts.fixedWeeks,
|
||||
numberOfMonths: this.opts.numberOfMonths,
|
||||
setMonths: (months) => (this.months = months),
|
||||
});
|
||||
/**
|
||||
* Updates the displayed months based on changes in the options values,
|
||||
* which determines the month to show in the calendar.
|
||||
*/
|
||||
useMonthViewOptionsSync({
|
||||
fixedWeeks: this.opts.fixedWeeks,
|
||||
locale: this.opts.locale,
|
||||
numberOfMonths: this.opts.numberOfMonths,
|
||||
placeholder: this.opts.placeholder,
|
||||
setMonths: this.setMonths,
|
||||
weekStartsOn: this.opts.weekStartsOn,
|
||||
});
|
||||
/**
|
||||
* Update the accessible heading's text content when the `fullCalendarLabel`
|
||||
* changes.
|
||||
*/
|
||||
watch(() => this.fullCalendarLabel, (label) => {
|
||||
const node = this.domContext.getElementById(this.accessibleHeadingId);
|
||||
if (!node)
|
||||
return;
|
||||
node.textContent = label;
|
||||
});
|
||||
/**
|
||||
* Synchronize the placeholder value with the current value.
|
||||
*/
|
||||
watch(() => this.opts.value.current, () => {
|
||||
const value = this.opts.value.current;
|
||||
if (Array.isArray(value) && value.length) {
|
||||
const lastValue = value[value.length - 1];
|
||||
if (lastValue && this.opts.placeholder.current !== lastValue) {
|
||||
this.opts.placeholder.current = lastValue;
|
||||
}
|
||||
}
|
||||
else if (!Array.isArray(value) &&
|
||||
value &&
|
||||
this.opts.placeholder.current !== value) {
|
||||
this.opts.placeholder.current = value;
|
||||
}
|
||||
});
|
||||
useEnsureNonDisabledPlaceholder({
|
||||
placeholder: opts.placeholder,
|
||||
defaultPlaceholder: opts.defaultPlaceholder,
|
||||
isDateDisabled: opts.isDateDisabled,
|
||||
maxValue: opts.maxValue,
|
||||
minValue: opts.minValue,
|
||||
ref: opts.ref,
|
||||
});
|
||||
}
|
||||
setMonths(months) {
|
||||
this.months = months;
|
||||
}
|
||||
/**
|
||||
* This derived state holds an array of localized day names for the current
|
||||
* locale and calendar view. It dynamically syncs with the 'weekStartsOn' option,
|
||||
* updating its content when the option changes. Using this state to render the
|
||||
* calendar's days of the week is strongly recommended, as it guarantees that
|
||||
* the days are correctly formatted for the current locale and calendar view.
|
||||
*/
|
||||
weekdays = $derived.by(() => {
|
||||
return getWeekdays({
|
||||
months: this.months,
|
||||
formatter: this.formatter,
|
||||
weekdayFormat: this.opts.weekdayFormat.current,
|
||||
});
|
||||
});
|
||||
initialPlaceholderYear = $derived.by(() => untrack(() => this.opts.placeholder.current.year));
|
||||
defaultYears = $derived.by(() => {
|
||||
return getDefaultYears({
|
||||
minValue: this.opts.minValue.current,
|
||||
maxValue: this.opts.maxValue.current,
|
||||
placeholderYear: this.initialPlaceholderYear,
|
||||
});
|
||||
});
|
||||
#setupInitialFocusEffect() {
|
||||
$effect(() => {
|
||||
const initialFocus = untrack(() => this.opts.initialFocus.current);
|
||||
if (initialFocus) {
|
||||
// focus the first `data-focused` day node
|
||||
const firstFocusedDay = this.opts.ref.current?.querySelector(`[data-focused]`);
|
||||
if (firstFocusedDay) {
|
||||
firstFocusedDay.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#setupAccessibleHeadingEffect() {
|
||||
$effect(() => {
|
||||
if (!this.opts.ref.current)
|
||||
return;
|
||||
const removeHeading = createAccessibleHeading({
|
||||
calendarNode: this.opts.ref.current,
|
||||
label: this.fullCalendarLabel,
|
||||
accessibleHeadingId: this.accessibleHeadingId,
|
||||
});
|
||||
return removeHeading;
|
||||
});
|
||||
}
|
||||
#setupFormatterEffect() {
|
||||
$effect.pre(() => {
|
||||
if (this.formatter.getLocale() === this.opts.locale.current)
|
||||
return;
|
||||
this.formatter.setLocale(this.opts.locale.current);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Navigates to the next page of the calendar.
|
||||
*/
|
||||
nextPage() {
|
||||
handleCalendarNextPage({
|
||||
fixedWeeks: this.opts.fixedWeeks.current,
|
||||
locale: this.opts.locale.current,
|
||||
numberOfMonths: this.opts.numberOfMonths.current,
|
||||
pagedNavigation: this.opts.pagedNavigation.current,
|
||||
setMonths: this.setMonths,
|
||||
setPlaceholder: (date) => (this.opts.placeholder.current = date),
|
||||
weekStartsOn: this.opts.weekStartsOn.current,
|
||||
months: this.months,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Navigates to the previous page of the calendar.
|
||||
*/
|
||||
prevPage() {
|
||||
handleCalendarPrevPage({
|
||||
fixedWeeks: this.opts.fixedWeeks.current,
|
||||
locale: this.opts.locale.current,
|
||||
numberOfMonths: this.opts.numberOfMonths.current,
|
||||
pagedNavigation: this.opts.pagedNavigation.current,
|
||||
setMonths: this.setMonths,
|
||||
setPlaceholder: (date) => (this.opts.placeholder.current = date),
|
||||
weekStartsOn: this.opts.weekStartsOn.current,
|
||||
months: this.months,
|
||||
});
|
||||
}
|
||||
nextYear() {
|
||||
this.opts.placeholder.current = this.opts.placeholder.current.add({ years: 1 });
|
||||
}
|
||||
prevYear() {
|
||||
this.opts.placeholder.current = this.opts.placeholder.current.subtract({ years: 1 });
|
||||
}
|
||||
setYear(year) {
|
||||
this.opts.placeholder.current = this.opts.placeholder.current.set({ year });
|
||||
}
|
||||
setMonth(month) {
|
||||
this.opts.placeholder.current = this.opts.placeholder.current.set({ month });
|
||||
}
|
||||
isNextButtonDisabled = $derived.by(() => {
|
||||
return getIsNextButtonDisabled({
|
||||
maxValue: this.opts.maxValue.current,
|
||||
months: this.months,
|
||||
disabled: this.opts.disabled.current,
|
||||
});
|
||||
});
|
||||
isPrevButtonDisabled = $derived.by(() => {
|
||||
return getIsPrevButtonDisabled({
|
||||
minValue: this.opts.minValue.current,
|
||||
months: this.months,
|
||||
disabled: this.opts.disabled.current,
|
||||
});
|
||||
});
|
||||
isInvalid = $derived.by(() => {
|
||||
const value = this.opts.value.current;
|
||||
const isDateDisabled = this.opts.isDateDisabled.current;
|
||||
const isDateUnavailable = this.opts.isDateUnavailable.current;
|
||||
if (Array.isArray(value)) {
|
||||
if (!value.length)
|
||||
return false;
|
||||
for (const date of value) {
|
||||
if (isDateDisabled(date))
|
||||
return true;
|
||||
if (isDateUnavailable(date))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!value)
|
||||
return false;
|
||||
if (isDateDisabled(value))
|
||||
return true;
|
||||
if (isDateUnavailable(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
headingValue = $derived.by(() => {
|
||||
this.opts.monthFormat.current;
|
||||
this.opts.yearFormat.current;
|
||||
return getCalendarHeadingValue({
|
||||
months: this.months,
|
||||
formatter: this.formatter,
|
||||
locale: this.opts.locale.current,
|
||||
});
|
||||
});
|
||||
fullCalendarLabel = $derived.by(() => {
|
||||
return `${this.opts.calendarLabel.current} ${this.headingValue}`;
|
||||
});
|
||||
isOutsideVisibleMonths(date) {
|
||||
return !this.visibleMonths.some((month) => isSameMonth(date, month));
|
||||
}
|
||||
isDateDisabled(date) {
|
||||
if (this.opts.isDateDisabled.current(date) || this.opts.disabled.current)
|
||||
return true;
|
||||
const minValue = this.opts.minValue.current;
|
||||
const maxValue = this.opts.maxValue.current;
|
||||
if (minValue && isBefore(date, minValue))
|
||||
return true;
|
||||
if (maxValue && isBefore(maxValue, date))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
isDateSelected(date) {
|
||||
const value = this.opts.value.current;
|
||||
if (Array.isArray(value)) {
|
||||
return value.some((d) => isSameDay(d, date));
|
||||
}
|
||||
else if (!value) {
|
||||
return false;
|
||||
}
|
||||
return isSameDay(value, date);
|
||||
}
|
||||
shiftFocus(node, add) {
|
||||
return shiftCalendarFocus({
|
||||
node,
|
||||
add,
|
||||
placeholder: this.opts.placeholder,
|
||||
calendarNode: this.opts.ref.current,
|
||||
isPrevButtonDisabled: this.isPrevButtonDisabled,
|
||||
isNextButtonDisabled: this.isNextButtonDisabled,
|
||||
months: this.months,
|
||||
numberOfMonths: this.opts.numberOfMonths.current,
|
||||
});
|
||||
}
|
||||
#isMultipleSelectionValid(selectedDates) {
|
||||
// only validate for multiple type and when maxDays is set
|
||||
if (this.opts.type.current !== "multiple")
|
||||
return true;
|
||||
if (!this.opts.maxDays.current)
|
||||
return true;
|
||||
const selectedCount = selectedDates.length;
|
||||
if (this.opts.maxDays.current && selectedCount > this.opts.maxDays.current)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
handleCellClick(_, date) {
|
||||
if (this.opts.readonly.current ||
|
||||
this.opts.isDateDisabled.current?.(date) ||
|
||||
this.opts.isDateUnavailable.current?.(date)) {
|
||||
return;
|
||||
}
|
||||
const prev = this.opts.value.current;
|
||||
const multiple = this.opts.type.current === "multiple";
|
||||
if (multiple) {
|
||||
if (Array.isArray(prev) || prev === undefined) {
|
||||
this.opts.value.current = this.handleMultipleUpdate(prev, date);
|
||||
}
|
||||
}
|
||||
else if (!Array.isArray(prev)) {
|
||||
const next = this.handleSingleUpdate(prev, date);
|
||||
if (!next) {
|
||||
this.announcer.announce("Selected date is now empty.", "polite", 5000);
|
||||
}
|
||||
else {
|
||||
this.announcer.announce(`Selected Date: ${this.formatter.selectedDate(next, false)}`, "polite");
|
||||
}
|
||||
this.opts.value.current = getDateWithPreviousTime(next, prev);
|
||||
if (next !== undefined) {
|
||||
this.opts.onDateSelect?.current?.();
|
||||
}
|
||||
}
|
||||
}
|
||||
handleMultipleUpdate(prev, date) {
|
||||
if (!prev) {
|
||||
const newSelection = [date];
|
||||
return this.#isMultipleSelectionValid(newSelection) ? newSelection : [date];
|
||||
}
|
||||
if (!Array.isArray(prev)) {
|
||||
if (DEV)
|
||||
throw new Error("Invalid value for multiple prop.");
|
||||
return;
|
||||
}
|
||||
const index = prev.findIndex((d) => isSameDay(d, date));
|
||||
const preventDeselect = this.opts.preventDeselect.current;
|
||||
if (index === -1) {
|
||||
// adding a new date - check if it would be valid
|
||||
const newSelection = [...prev, date];
|
||||
if (this.#isMultipleSelectionValid(newSelection)) {
|
||||
return newSelection;
|
||||
}
|
||||
else {
|
||||
// reset to just the newly selected date when constraints are violated
|
||||
return [date];
|
||||
}
|
||||
}
|
||||
else if (preventDeselect) {
|
||||
return prev;
|
||||
}
|
||||
else {
|
||||
const next = prev.filter((d) => !isSameDay(d, date));
|
||||
if (!next.length) {
|
||||
this.opts.placeholder.current = date;
|
||||
return undefined;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
}
|
||||
handleSingleUpdate(prev, date) {
|
||||
if (Array.isArray(prev)) {
|
||||
if (DEV)
|
||||
throw new Error("Invalid value for single prop.");
|
||||
}
|
||||
if (!prev)
|
||||
return date;
|
||||
const preventDeselect = this.opts.preventDeselect.current;
|
||||
if (!preventDeselect && isSameDay(prev, date)) {
|
||||
this.opts.placeholder.current = date;
|
||||
return undefined;
|
||||
}
|
||||
return date;
|
||||
}
|
||||
onkeydown(event) {
|
||||
handleCalendarKeydown({
|
||||
event,
|
||||
handleCellClick: this.handleCellClick,
|
||||
shiftFocus: this.shiftFocus,
|
||||
placeholderValue: this.opts.placeholder.current,
|
||||
});
|
||||
}
|
||||
snippetProps = $derived.by(() => ({
|
||||
months: this.months,
|
||||
weekdays: this.weekdays,
|
||||
}));
|
||||
getBitsAttr = (part) => {
|
||||
return calendarAttrs.getAttr(part);
|
||||
};
|
||||
props = $derived.by(() => ({
|
||||
...getCalendarElementProps({
|
||||
fullCalendarLabel: this.fullCalendarLabel,
|
||||
id: this.opts.id.current,
|
||||
isInvalid: this.isInvalid,
|
||||
disabled: this.opts.disabled.current,
|
||||
readonly: this.opts.readonly.current,
|
||||
}),
|
||||
[this.getBitsAttr("root")]: "",
|
||||
//
|
||||
onkeydown: this.onkeydown,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarHeadingState {
|
||||
static create(opts) {
|
||||
return new CalendarHeadingState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"aria-hidden": boolToStrTrueOrUndef(true),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
[this.root.getBitsAttr("heading")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
const CalendarCellContext = new Context("Calendar.Cell | RangeCalendar.Cell");
|
||||
export class CalendarCellState {
|
||||
static create(opts) {
|
||||
return CalendarCellContext.set(new CalendarCellState(opts, CalendarRootContext.get()));
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
cellDate = $derived.by(() => toDate(this.opts.date.current));
|
||||
isUnavailable = $derived.by(() => this.root.opts.isDateUnavailable.current(this.opts.date.current));
|
||||
isDateToday = $derived.by(() => isToday(this.opts.date.current, getLocalTimeZone()));
|
||||
isOutsideMonth = $derived.by(() => !isSameMonth(this.opts.date.current, this.opts.month.current));
|
||||
isOutsideVisibleMonths = $derived.by(() => this.root.isOutsideVisibleMonths(this.opts.date.current));
|
||||
isDisabled = $derived.by(() => this.root.isDateDisabled(this.opts.date.current) ||
|
||||
(this.isOutsideMonth && this.root.opts.disableDaysOutsideMonth.current));
|
||||
isFocusedDate = $derived.by(() => isSameDay(this.opts.date.current, this.root.opts.placeholder.current));
|
||||
isSelectedDate = $derived.by(() => this.root.isDateSelected(this.opts.date.current));
|
||||
labelText = $derived.by(() => this.root.formatter.custom(this.cellDate, {
|
||||
weekday: "long",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
}));
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
snippetProps = $derived.by(() => ({
|
||||
disabled: this.isDisabled,
|
||||
unavailable: this.isUnavailable,
|
||||
selected: this.isSelectedDate,
|
||||
day: `${this.opts.date.current.day}`,
|
||||
}));
|
||||
ariaDisabled = $derived.by(() => {
|
||||
return (this.isDisabled ||
|
||||
(this.isOutsideMonth && this.root.opts.disableDaysOutsideMonth.current) ||
|
||||
this.isUnavailable);
|
||||
});
|
||||
sharedDataAttrs = $derived.by(() => ({
|
||||
"data-unavailable": boolToEmptyStrOrUndef(this.isUnavailable),
|
||||
"data-today": this.isDateToday ? "" : undefined,
|
||||
"data-outside-month": this.isOutsideMonth ? "" : undefined,
|
||||
"data-outside-visible-months": this.isOutsideVisibleMonths ? "" : undefined,
|
||||
"data-focused": this.isFocusedDate ? "" : undefined,
|
||||
"data-selected": boolToEmptyStrOrUndef(this.isSelectedDate),
|
||||
"data-value": this.opts.date.current.toString(),
|
||||
"data-type": getDateValueType(this.opts.date.current),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.isDisabled ||
|
||||
(this.isOutsideMonth && this.root.opts.disableDaysOutsideMonth.current)),
|
||||
}));
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: "gridcell",
|
||||
"aria-selected": boolToStr(this.isSelectedDate),
|
||||
"aria-disabled": boolToStr(this.ariaDisabled),
|
||||
...this.sharedDataAttrs,
|
||||
[this.root.getBitsAttr("cell")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarDayState {
|
||||
static create(opts) {
|
||||
return new CalendarDayState(opts, CalendarCellContext.get());
|
||||
}
|
||||
opts;
|
||||
cell;
|
||||
attachment;
|
||||
constructor(opts, cell) {
|
||||
this.opts = opts;
|
||||
this.cell = cell;
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
#tabindex = $derived.by(() => (this.cell.isOutsideMonth && this.cell.root.opts.disableDaysOutsideMonth.current) ||
|
||||
this.cell.isDisabled
|
||||
? undefined
|
||||
: this.cell.isFocusedDate
|
||||
? 0
|
||||
: -1);
|
||||
onclick(e) {
|
||||
if (this.cell.isDisabled)
|
||||
return;
|
||||
this.cell.root.handleCellClick(e, this.cell.opts.date.current);
|
||||
}
|
||||
snippetProps = $derived.by(() => ({
|
||||
disabled: this.cell.isDisabled,
|
||||
unavailable: this.cell.isUnavailable,
|
||||
selected: this.cell.isSelectedDate,
|
||||
day: `${this.cell.opts.date.current.day}`,
|
||||
}));
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: "button",
|
||||
"aria-label": this.cell.labelText,
|
||||
"aria-disabled": boolToStr(this.cell.ariaDisabled),
|
||||
...this.cell.sharedDataAttrs,
|
||||
tabindex: this.#tabindex,
|
||||
[this.cell.root.getBitsAttr("day")]: "",
|
||||
// Shared logic for range calendar and calendar
|
||||
"data-bits-day": "",
|
||||
//
|
||||
onclick: this.onclick,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarNextButtonState {
|
||||
static create(opts) {
|
||||
return new CalendarNextButtonState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
isDisabled = $derived.by(() => this.root.isNextButtonDisabled);
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
onclick(_) {
|
||||
if (this.isDisabled)
|
||||
return;
|
||||
this.root.nextPage();
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: "button",
|
||||
type: "button",
|
||||
"aria-label": "Next",
|
||||
"aria-disabled": boolToStr(this.isDisabled),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.isDisabled),
|
||||
disabled: this.isDisabled,
|
||||
[this.root.getBitsAttr("next-button")]: "",
|
||||
//
|
||||
onclick: this.onclick,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarPrevButtonState {
|
||||
static create(opts) {
|
||||
return new CalendarPrevButtonState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
isDisabled = $derived.by(() => this.root.isPrevButtonDisabled);
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.onclick = this.onclick.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
onclick(_) {
|
||||
if (this.isDisabled)
|
||||
return;
|
||||
this.root.prevPage();
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
role: "button",
|
||||
type: "button",
|
||||
"aria-label": "Previous",
|
||||
"aria-disabled": boolToStr(this.isDisabled),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.isDisabled),
|
||||
disabled: this.isDisabled,
|
||||
[this.root.getBitsAttr("prev-button")]: "",
|
||||
//
|
||||
onclick: this.onclick,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarGridState {
|
||||
static create(opts) {
|
||||
return new CalendarGridState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
tabindex: -1,
|
||||
role: "grid",
|
||||
"aria-readonly": boolToStr(this.root.opts.readonly.current),
|
||||
"aria-disabled": boolToStr(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
[this.root.getBitsAttr("grid")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarGridBodyState {
|
||||
static create(opts) {
|
||||
return new CalendarGridBodyState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
[this.root.getBitsAttr("grid-body")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarGridHeadState {
|
||||
static create(opts) {
|
||||
return new CalendarGridHeadState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
[this.root.getBitsAttr("grid-head")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarGridRowState {
|
||||
static create(opts) {
|
||||
return new CalendarGridRowState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
[this.root.getBitsAttr("grid-row")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarHeadCellState {
|
||||
static create(opts) {
|
||||
return new CalendarHeadCellState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
[this.root.getBitsAttr("head-cell")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarHeaderState {
|
||||
static create(opts) {
|
||||
return new CalendarHeaderState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
|
||||
"data-readonly": boolToEmptyStrOrUndef(this.root.opts.readonly.current),
|
||||
[this.root.getBitsAttr("header")]: "",
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarMonthSelectState {
|
||||
static create(opts) {
|
||||
return new CalendarMonthSelectState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.onchange = this.onchange.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
monthItems = $derived.by(() => {
|
||||
this.root.opts.locale.current;
|
||||
const monthNumbers = this.opts.months.current;
|
||||
const monthFormat = this.opts.monthFormat.current;
|
||||
const months = [];
|
||||
for (const month of monthNumbers) {
|
||||
// create a date with the current year and the month to get localized name
|
||||
const date = this.root.opts.placeholder.current.set({ month });
|
||||
let label;
|
||||
if (typeof monthFormat === "function") {
|
||||
label = monthFormat(month);
|
||||
}
|
||||
else {
|
||||
label = this.root.formatter.custom(toDate(date), { month: monthFormat });
|
||||
}
|
||||
months.push({
|
||||
value: month,
|
||||
label,
|
||||
});
|
||||
}
|
||||
return months;
|
||||
});
|
||||
currentMonth = $derived.by(() => this.root.opts.placeholder.current.month);
|
||||
isDisabled = $derived.by(() => this.root.opts.disabled.current || this.opts.disabled.current);
|
||||
snippetProps = $derived.by(() => {
|
||||
return {
|
||||
monthItems: this.monthItems,
|
||||
selectedMonthItem: this.monthItems.find((month) => month.value === this.currentMonth),
|
||||
};
|
||||
});
|
||||
onchange(event) {
|
||||
if (this.isDisabled)
|
||||
return;
|
||||
const target = event.target;
|
||||
const month = parseInt(target.value, 10);
|
||||
if (!isNaN(month)) {
|
||||
this.root.opts.placeholder.current = this.root.opts.placeholder.current.set({ month });
|
||||
}
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
value: this.currentMonth,
|
||||
disabled: this.isDisabled,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.isDisabled),
|
||||
[this.root.getBitsAttr("month-select")]: "",
|
||||
//
|
||||
onchange: this.onchange,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
export class CalendarYearSelectState {
|
||||
static create(opts) {
|
||||
return new CalendarYearSelectState(opts, CalendarRootContext.get());
|
||||
}
|
||||
opts;
|
||||
root;
|
||||
attachment;
|
||||
constructor(opts, root) {
|
||||
this.opts = opts;
|
||||
this.root = root;
|
||||
this.onchange = this.onchange.bind(this);
|
||||
this.attachment = attachRef(this.opts.ref);
|
||||
}
|
||||
years = $derived.by(() => {
|
||||
if (this.opts.years.current && this.opts.years.current.length)
|
||||
return this.opts.years.current;
|
||||
return this.root.defaultYears;
|
||||
});
|
||||
yearItems = $derived.by(() => {
|
||||
this.root.opts.locale.current;
|
||||
const yearFormat = this.opts.yearFormat.current;
|
||||
const localYears = [];
|
||||
for (const year of this.years) {
|
||||
// create a date with the year to get localized formatting
|
||||
const date = this.root.opts.placeholder.current.set({ year });
|
||||
let label;
|
||||
if (typeof yearFormat === "function") {
|
||||
label = yearFormat(year);
|
||||
}
|
||||
else {
|
||||
label = this.root.formatter.custom(toDate(date), { year: yearFormat });
|
||||
}
|
||||
localYears.push({
|
||||
value: year,
|
||||
label,
|
||||
});
|
||||
}
|
||||
return localYears;
|
||||
});
|
||||
currentYear = $derived.by(() => this.root.opts.placeholder.current.year);
|
||||
isDisabled = $derived.by(() => this.root.opts.disabled.current || this.opts.disabled.current);
|
||||
snippetProps = $derived.by(() => {
|
||||
return {
|
||||
yearItems: this.yearItems,
|
||||
selectedYearItem: this.yearItems.find((year) => year.value === this.currentYear),
|
||||
};
|
||||
});
|
||||
onchange(event) {
|
||||
if (this.isDisabled)
|
||||
return;
|
||||
const target = event.target;
|
||||
const year = parseInt(target.value, 10);
|
||||
if (!isNaN(year)) {
|
||||
this.root.opts.placeholder.current = this.root.opts.placeholder.current.set({ year });
|
||||
}
|
||||
}
|
||||
props = $derived.by(() => ({
|
||||
id: this.opts.id.current,
|
||||
value: this.currentYear,
|
||||
disabled: this.isDisabled,
|
||||
"data-disabled": boolToEmptyStrOrUndef(this.isDisabled),
|
||||
[this.root.getBitsAttr("year-select")]: "",
|
||||
//
|
||||
onchange: this.onchange,
|
||||
...this.attachment,
|
||||
}));
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarCellState } from "../calendar.svelte.js";
|
||||
import type { CalendarCellProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
date,
|
||||
month,
|
||||
...restProps
|
||||
}: CalendarCellProps = $props();
|
||||
|
||||
const cellState = CalendarCellState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
date: boxWith(() => date),
|
||||
month: boxWith(() => month),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, cellState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({
|
||||
props: mergedProps,
|
||||
...cellState.snippetProps,
|
||||
})}
|
||||
{:else}
|
||||
<td {...mergedProps}>
|
||||
{@render children?.(cellState.snippetProps)}
|
||||
</td>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarCellProps } from "../types.js";
|
||||
declare const CalendarCell: import("svelte").Component<CalendarCellProps, {}, "ref">;
|
||||
type CalendarCell = ReturnType<typeof CalendarCell>;
|
||||
export default CalendarCell;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarDayState } from "../calendar.svelte.js";
|
||||
import type { CalendarDayProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarDayProps = $props();
|
||||
|
||||
const dayState = CalendarDayState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, dayState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({
|
||||
props: mergedProps,
|
||||
...dayState.snippetProps,
|
||||
})}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{#if children}
|
||||
{@render children?.(dayState.snippetProps)}
|
||||
{:else}
|
||||
{dayState.cell.opts.date.current.day}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarDayProps } from "../types.js";
|
||||
declare const CalendarDay: import("svelte").Component<CalendarDayProps, {}, "ref">;
|
||||
type CalendarDay = ReturnType<typeof CalendarDay>;
|
||||
export default CalendarDay;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { CalendarGridBodyProps } from "../types.js";
|
||||
import { CalendarGridBodyState } from "../calendar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarGridBodyProps = $props();
|
||||
|
||||
const gridBodyState = CalendarGridBodyState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, gridBodyState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<tbody {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</tbody>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarGridBodyProps } from "../types.js";
|
||||
declare const CalendarGridBody: import("svelte").Component<CalendarGridBodyProps, {}, "ref">;
|
||||
type CalendarGridBody = ReturnType<typeof CalendarGridBody>;
|
||||
export default CalendarGridBody;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarGridHeadState } from "../calendar.svelte.js";
|
||||
import type { CalendarGridHeadProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarGridHeadProps = $props();
|
||||
|
||||
const gridHeadState = CalendarGridHeadState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, gridHeadState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<thead {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</thead>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarGridHeadProps } from "../types.js";
|
||||
declare const CalendarGridHead: import("svelte").Component<CalendarGridHeadProps, {}, "ref">;
|
||||
type CalendarGridHead = ReturnType<typeof CalendarGridHead>;
|
||||
export default CalendarGridHead;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarGridRowState } from "../calendar.svelte.js";
|
||||
import type { CalendarGridRowProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarGridRowProps = $props();
|
||||
|
||||
const gridRowState = CalendarGridRowState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, gridRowState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<tr {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</tr>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarGridRowProps } from "../types.js";
|
||||
declare const CalendarGridRow: import("svelte").Component<CalendarGridRowProps, {}, "ref">;
|
||||
type CalendarGridRow = ReturnType<typeof CalendarGridRow>;
|
||||
export default CalendarGridRow;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarGridState } from "../calendar.svelte.js";
|
||||
import type { CalendarGridProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarGridProps = $props();
|
||||
|
||||
const gridState = CalendarGridState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, gridState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<table {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</table>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarGridProps } from "../types.js";
|
||||
declare const CalendarGrid: import("svelte").Component<CalendarGridProps, {}, "ref">;
|
||||
type CalendarGrid = ReturnType<typeof CalendarGrid>;
|
||||
export default CalendarGrid;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarHeadCellState } from "../calendar.svelte.js";
|
||||
import type { CalendarHeadCellProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarHeadCellProps = $props();
|
||||
|
||||
const headCellState = CalendarHeadCellState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, headCellState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<th {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</th>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarHeadCellProps } from "../types.js";
|
||||
declare const CalendarHeadCell: import("svelte").Component<CalendarHeadCellProps, {}, "ref">;
|
||||
type CalendarHeadCell = ReturnType<typeof CalendarHeadCell>;
|
||||
export default CalendarHeadCell;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarHeaderState } from "../calendar.svelte.js";
|
||||
import type { CalendarHeaderProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarHeaderProps = $props();
|
||||
|
||||
const headerState = CalendarHeaderState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, headerState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<header {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</header>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarHeaderProps } from "../types.js";
|
||||
declare const CalendarHeader: import("svelte").Component<CalendarHeaderProps, {}, "ref">;
|
||||
type CalendarHeader = ReturnType<typeof CalendarHeader>;
|
||||
export default CalendarHeader;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { CalendarHeadingProps } from "../types.js";
|
||||
import { CalendarHeadingState } from "../calendar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
...restProps
|
||||
}: CalendarHeadingProps = $props();
|
||||
|
||||
const headingState = CalendarHeadingState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, headingState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps, headingValue: headingState.root.headingValue })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{#if children}
|
||||
{@render children?.({ headingValue: headingState.root.headingValue })}
|
||||
{:else}
|
||||
{headingState.root.headingValue}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarHeadingProps } from "../types.js";
|
||||
declare const CalendarHeading: import("svelte").Component<CalendarHeadingProps, {}, "ref">;
|
||||
type CalendarHeading = ReturnType<typeof CalendarHeading>;
|
||||
export default CalendarHeading;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { CalendarMonthSelectProps } from "../types.js";
|
||||
import { CalendarMonthSelectState } from "../calendar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
monthFormat = "long",
|
||||
disabled = false,
|
||||
"aria-label": ariaLabel = "Select a month",
|
||||
...restProps
|
||||
}: CalendarMonthSelectProps = $props();
|
||||
|
||||
const monthSelectState = CalendarMonthSelectState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
months: boxWith(() => months),
|
||||
monthFormat: boxWith(() => monthFormat),
|
||||
disabled: boxWith(() => Boolean(disabled)),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, monthSelectState.props, { "aria-label": ariaLabel })
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps, ...monthSelectState.snippetProps })}
|
||||
{:else}
|
||||
<select {...mergedProps}>
|
||||
{#if children}
|
||||
{@render children?.(monthSelectState.snippetProps)}
|
||||
{:else}
|
||||
{#each monthSelectState.monthItems as month (month.value)}
|
||||
<option
|
||||
value={month.value}
|
||||
selected={month.value === monthSelectState.currentMonth}
|
||||
>
|
||||
{month.label}
|
||||
</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarMonthSelectProps } from "../types.js";
|
||||
declare const CalendarMonthSelect: import("svelte").Component<CalendarMonthSelectProps, {}, "ref">;
|
||||
type CalendarMonthSelect = ReturnType<typeof CalendarMonthSelect>;
|
||||
export default CalendarMonthSelect;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { CalendarNextButtonState } from "../calendar.svelte.js";
|
||||
import type { CalendarNextButtonProps } from "../types.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
// for safari
|
||||
tabindex = 0,
|
||||
...restProps
|
||||
}: CalendarNextButtonProps = $props();
|
||||
|
||||
const nextButtonState = CalendarNextButtonState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, nextButtonState.props, { tabindex }));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarNextButtonProps } from "../types.js";
|
||||
declare const CalendarNextButton: import("svelte").Component<CalendarNextButtonProps, {}, "ref">;
|
||||
type CalendarNextButton = ReturnType<typeof CalendarNextButton>;
|
||||
export default CalendarNextButton;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { CalendarPrevButtonProps } from "../types.js";
|
||||
import { CalendarPrevButtonState } from "../calendar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
id = createId(uid),
|
||||
ref = $bindable(null),
|
||||
// for safari
|
||||
tabindex = 0,
|
||||
...restProps
|
||||
}: CalendarPrevButtonProps = $props();
|
||||
|
||||
const prevButtonState = CalendarPrevButtonState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, prevButtonState.props, { tabindex }));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps })}
|
||||
{:else}
|
||||
<button {...mergedProps}>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarPrevButtonProps } from "../types.js";
|
||||
declare const CalendarPrevButton: import("svelte").Component<CalendarPrevButtonProps, {}, "ref">;
|
||||
type CalendarPrevButton = ReturnType<typeof CalendarPrevButton>;
|
||||
export default CalendarPrevButton;
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<script lang="ts">
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import type { CalendarYearSelectProps } from "../types.js";
|
||||
import { CalendarYearSelectState } from "../calendar.svelte.js";
|
||||
import { createId } from "../../../internal/create-id.js";
|
||||
|
||||
const uid = $props.id();
|
||||
|
||||
let {
|
||||
children,
|
||||
child,
|
||||
ref = $bindable(null),
|
||||
id = createId(uid),
|
||||
years,
|
||||
yearFormat = "numeric",
|
||||
disabled = false,
|
||||
"aria-label": ariaLabel = "Select a year",
|
||||
...restProps
|
||||
}: CalendarYearSelectProps = $props();
|
||||
|
||||
const yearSelectState = CalendarYearSelectState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
years: boxWith(() => years),
|
||||
yearFormat: boxWith(() => yearFormat),
|
||||
disabled: boxWith(() => Boolean(disabled)),
|
||||
});
|
||||
|
||||
const mergedProps = $derived(
|
||||
mergeProps(restProps, yearSelectState.props, { "aria-label": ariaLabel })
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps, ...yearSelectState.snippetProps })}
|
||||
{:else}
|
||||
<select {...mergedProps}>
|
||||
{#if children}
|
||||
{@render children?.(yearSelectState.snippetProps)}
|
||||
{:else}
|
||||
{#each yearSelectState.yearItems as year (year.value)}
|
||||
<option value={year.value} selected={year.value === yearSelectState.currentYear}>
|
||||
{year.label}
|
||||
</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
{/if}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarYearSelectProps } from "../types.js";
|
||||
declare const CalendarYearSelect: import("svelte").Component<CalendarYearSelectProps, {}, "ref">;
|
||||
type CalendarYearSelect = ReturnType<typeof CalendarYearSelect>;
|
||||
export default CalendarYearSelect;
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
<script lang="ts">
|
||||
import { watch } from "runed";
|
||||
import { boxWith, mergeProps } from "svelte-toolbelt";
|
||||
import { type DateValue } from "@internationalized/date";
|
||||
import { CalendarRootState } from "../calendar.svelte.js";
|
||||
import type { CalendarRootProps } from "../types.js";
|
||||
import { useId } from "../../../internal/use-id.js";
|
||||
import { noop } from "../../../internal/noop.js";
|
||||
import { getDefaultDate } from "../../../internal/date-time/utils.js";
|
||||
import { resolveLocaleProp } from "../../utilities/config/prop-resolvers.js";
|
||||
|
||||
let {
|
||||
child,
|
||||
children,
|
||||
id = useId(),
|
||||
ref = $bindable(null),
|
||||
value = $bindable(),
|
||||
onValueChange = noop,
|
||||
placeholder = $bindable(),
|
||||
onPlaceholderChange = noop,
|
||||
weekdayFormat = "narrow",
|
||||
weekStartsOn,
|
||||
pagedNavigation = false,
|
||||
isDateDisabled = () => false,
|
||||
isDateUnavailable = () => false,
|
||||
fixedWeeks = false,
|
||||
numberOfMonths = 1,
|
||||
locale,
|
||||
calendarLabel = "Event",
|
||||
disabled = false,
|
||||
readonly = false,
|
||||
minValue = undefined,
|
||||
maxValue = undefined,
|
||||
preventDeselect = false,
|
||||
type,
|
||||
disableDaysOutsideMonth = true,
|
||||
initialFocus = false,
|
||||
maxDays,
|
||||
monthFormat = "long",
|
||||
yearFormat = "numeric",
|
||||
...restProps
|
||||
}: CalendarRootProps = $props();
|
||||
|
||||
const defaultPlaceholder = getDefaultDate({
|
||||
defaultValue: value,
|
||||
minValue,
|
||||
maxValue,
|
||||
});
|
||||
|
||||
function handleDefaultPlaceholder() {
|
||||
if (placeholder !== undefined) return;
|
||||
placeholder = defaultPlaceholder;
|
||||
}
|
||||
|
||||
// SSR
|
||||
handleDefaultPlaceholder();
|
||||
|
||||
watch.pre(
|
||||
() => placeholder,
|
||||
() => {
|
||||
handleDefaultPlaceholder();
|
||||
}
|
||||
);
|
||||
|
||||
function handleDefaultValue() {
|
||||
if (value !== undefined) return;
|
||||
value = type === "single" ? undefined : [];
|
||||
}
|
||||
|
||||
// SSR
|
||||
handleDefaultValue();
|
||||
|
||||
watch.pre(
|
||||
() => value,
|
||||
() => {
|
||||
handleDefaultValue();
|
||||
}
|
||||
);
|
||||
|
||||
const rootState = CalendarRootState.create({
|
||||
id: boxWith(() => id),
|
||||
ref: boxWith(
|
||||
() => ref,
|
||||
(v) => (ref = v)
|
||||
),
|
||||
weekdayFormat: boxWith(() => weekdayFormat),
|
||||
weekStartsOn: boxWith(() => weekStartsOn),
|
||||
pagedNavigation: boxWith(() => pagedNavigation),
|
||||
isDateDisabled: boxWith(() => isDateDisabled),
|
||||
isDateUnavailable: boxWith(() => isDateUnavailable),
|
||||
fixedWeeks: boxWith(() => fixedWeeks),
|
||||
numberOfMonths: boxWith(() => numberOfMonths),
|
||||
locale: resolveLocaleProp(() => locale),
|
||||
calendarLabel: boxWith(() => calendarLabel),
|
||||
readonly: boxWith(() => readonly),
|
||||
disabled: boxWith(() => disabled),
|
||||
minValue: boxWith(() => minValue),
|
||||
maxValue: boxWith(() => maxValue),
|
||||
disableDaysOutsideMonth: boxWith(() => disableDaysOutsideMonth),
|
||||
initialFocus: boxWith(() => initialFocus),
|
||||
maxDays: boxWith(() => maxDays),
|
||||
placeholder: boxWith(
|
||||
() => placeholder as DateValue,
|
||||
(v) => {
|
||||
placeholder = v;
|
||||
onPlaceholderChange(v as DateValue);
|
||||
}
|
||||
),
|
||||
preventDeselect: boxWith(() => preventDeselect),
|
||||
value: boxWith(
|
||||
() => value,
|
||||
(v) => {
|
||||
value = v;
|
||||
// oxlint-disable-next-line no-explicit-any
|
||||
onValueChange(v as any);
|
||||
}
|
||||
),
|
||||
type: boxWith(() => type),
|
||||
monthFormat: boxWith(() => monthFormat),
|
||||
yearFormat: boxWith(() => yearFormat),
|
||||
defaultPlaceholder,
|
||||
});
|
||||
|
||||
const mergedProps = $derived(mergeProps(restProps, rootState.props));
|
||||
</script>
|
||||
|
||||
{#if child}
|
||||
{@render child({ props: mergedProps, ...rootState.snippetProps })}
|
||||
{:else}
|
||||
<div {...mergedProps}>
|
||||
{@render children?.(rootState.snippetProps)}
|
||||
</div>
|
||||
{/if}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import type { CalendarRootProps } from "../types.js";
|
||||
declare const Calendar: import("svelte").Component<CalendarRootProps, {}, "value" | "placeholder" | "ref">;
|
||||
type Calendar = ReturnType<typeof Calendar>;
|
||||
export default Calendar;
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
export { default as Root } from "./components/calendar.svelte";
|
||||
export { default as Day } from "./components/calendar-day.svelte";
|
||||
export { default as Grid } from "./components/calendar-grid.svelte";
|
||||
export { default as GridBody } from "./components/calendar-grid-body.svelte";
|
||||
export { default as Cell } from "./components/calendar-cell.svelte";
|
||||
export { default as GridHead } from "./components/calendar-grid-head.svelte";
|
||||
export { default as HeadCell } from "./components/calendar-head-cell.svelte";
|
||||
export { default as GridRow } from "./components/calendar-grid-row.svelte";
|
||||
export { default as Header } from "./components/calendar-header.svelte";
|
||||
export { default as Heading } from "./components/calendar-heading.svelte";
|
||||
export { default as MonthSelect } from "./components/calendar-month-select.svelte";
|
||||
export { default as NextButton } from "./components/calendar-next-button.svelte";
|
||||
export { default as PrevButton } from "./components/calendar-prev-button.svelte";
|
||||
export { default as YearSelect } from "./components/calendar-year-select.svelte";
|
||||
export type { CalendarRootProps as RootProps, CalendarPrevButtonProps as PrevButtonProps, CalendarNextButtonProps as NextButtonProps, CalendarHeadingProps as HeadingProps, CalendarHeaderProps as HeaderProps, CalendarGridProps as GridProps, CalendarGridHeadProps as GridHeadProps, CalendarHeadCellProps as HeadCellProps, CalendarGridBodyProps as GridBodyProps, CalendarGridRowProps as GridRowProps, CalendarCellProps as CellProps, CalendarDayProps as DayProps, CalendarMonthSelectProps as MonthSelectProps, CalendarYearSelectProps as YearSelectProps, } from "./types.js";
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
export { default as Root } from "./components/calendar.svelte";
|
||||
export { default as Day } from "./components/calendar-day.svelte";
|
||||
export { default as Grid } from "./components/calendar-grid.svelte";
|
||||
export { default as GridBody } from "./components/calendar-grid-body.svelte";
|
||||
export { default as Cell } from "./components/calendar-cell.svelte";
|
||||
export { default as GridHead } from "./components/calendar-grid-head.svelte";
|
||||
export { default as HeadCell } from "./components/calendar-head-cell.svelte";
|
||||
export { default as GridRow } from "./components/calendar-grid-row.svelte";
|
||||
export { default as Header } from "./components/calendar-header.svelte";
|
||||
export { default as Heading } from "./components/calendar-heading.svelte";
|
||||
export { default as MonthSelect } from "./components/calendar-month-select.svelte";
|
||||
export { default as NextButton } from "./components/calendar-next-button.svelte";
|
||||
export { default as PrevButton } from "./components/calendar-prev-button.svelte";
|
||||
export { default as YearSelect } from "./components/calendar-year-select.svelte";
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * as Calendar from "./exports.js";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user