@adriansyah/heroui-svelte 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +3 -3
  2. package/dist/components/autocomplete/autocomplete-popover.svelte +1 -1
  3. package/dist/components/autocomplete/autocomplete-trigger.svelte +45 -21
  4. package/dist/components/autocomplete/autocomplete-trigger.svelte.d.ts +8 -2
  5. package/dist/components/autocomplete/autocomplete.svelte +12 -6
  6. package/dist/components/autocomplete/index.svelte.d.ts +3 -3
  7. package/dist/components/autocomplete/index.svelte.js +10 -11
  8. package/dist/components/checkbox/checkbox-content.svelte +7 -6
  9. package/dist/components/checkbox/checkbox-control.svelte +7 -6
  10. package/dist/components/checkbox/checkbox.svelte +6 -1
  11. package/dist/components/filter/index.svelte.js +2 -17
  12. package/dist/components/list-box/index.svelte.d.ts +20 -0
  13. package/dist/components/list-box/index.svelte.js +55 -1
  14. package/dist/components/list-box/list-box-item-indicator.svelte +3 -9
  15. package/dist/components/list-box/list-box-item.svelte +23 -48
  16. package/dist/components/list-box/list-box-item.svelte.d.ts +4 -1
  17. package/dist/components/list-box/list-box.svelte +1 -2
  18. package/dist/components/modal/modal-trigger.svelte +18 -9
  19. package/dist/components/modal/modal-trigger.svelte.d.ts +5 -1
  20. package/dist/components/pagination/pagination-content.svelte +17 -1
  21. package/dist/components/pagination/pagination-link.svelte +5 -1
  22. package/dist/components/pagination/pagination-next.svelte +7 -1
  23. package/dist/components/pagination/pagination-previous.svelte +7 -1
  24. package/dist/components/pagination/pagination-summary.svelte +7 -1
  25. package/dist/components/pagination/pagination.svelte +8 -1
  26. package/dist/components/popover/index.svelte.d.ts +1 -1
  27. package/dist/components/popover/index.svelte.js +1 -1
  28. package/dist/components/popover/popover-trigger.svelte +26 -9
  29. package/dist/components/popover/popover-trigger.svelte.d.ts +12 -7
  30. package/dist/components/popover/popover.svelte +2 -2
  31. package/dist/components/popover/popover.svelte.d.ts +2 -4
  32. package/dist/components/search-input/search-input.svelte +4 -3
  33. package/package.json +2 -2
package/README.md CHANGED
@@ -5,7 +5,7 @@ A Svelte 5 wrapper for [HeroUI](https://heroui.com), bringing HeroUI's styling a
5
5
  ## Installation
6
6
 
7
7
  ```sh
8
- bun add github:adriansyah-kadir/heroui-svelte#release @heroui/styles
8
+ bun add @adriansyah/heroui-svelte @heroui/styles
9
9
  ```
10
10
 
11
11
  ## Setup
@@ -16,7 +16,7 @@ Import Tailwind CSS and HeroUI styles in your main CSS file:
16
16
  @import "tailwindcss";
17
17
  @import "@heroui/styles";
18
18
 
19
- @source "../../node_modules/heroui-svelte/dist";
19
+ @source "../../node_modules/@adriansyah/heroui-svelte/dist";
20
20
  ```
21
21
 
22
22
  Adjust the `@source` path to match your project structure.
@@ -27,7 +27,7 @@ Import components from `heroui-svelte` and use them in your Svelte 5 components.
27
27
 
28
28
  ```svelte
29
29
  <script lang="ts">
30
- import { Button } from "heroui-svelte";
30
+ import { Button } from "@adriansyah/heroui-svelte";
31
31
  </script>
32
32
 
33
33
  <Button>Get started</Button>
@@ -7,7 +7,7 @@
7
7
  const autocomplete = AutocompleteContext.get();
8
8
  </script>
9
9
 
10
- <PopoverContent popover="manual">
10
+ <PopoverContent {@attach autocomplete.popover.attach()} popover="manual">
11
11
  <div
12
12
  {...props}
13
13
  class={autocompleteVariants(autocomplete.heroui).popover({
@@ -1,28 +1,52 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
- import { PopoverContext } from "../../index.js";
3
+ import { AutocompleteContext } from "../../index.js";
4
4
  import { autocompleteVariants } from "@heroui/styles";
5
+ import AutocompleteClearButton from "./autocomplete-clear-button.svelte";
6
+ import AutocompleteIndicator from "./autocomplete-indicator.svelte";
7
+ import AutocompleteValue from "./autocomplete-value.svelte";
8
+ import type { Snippet } from "svelte";
5
9
 
6
- interface Props extends HTMLAttributes<HTMLDivElement> {}
10
+ type Props = HTMLAttributes<HTMLDivElement> & {
11
+ child?: Snippet<[{ props: HTMLAttributes<any>; ctx: AutocompleteContext }]>;
12
+ };
7
13
 
8
- const { children, ...props }: Props = $props();
9
- const { popover } = PopoverContext.get();
14
+ const { children, child, ...props }: Props = $props();
15
+ const ctx = AutocompleteContext.get();
16
+ const popover = ctx.popover;
17
+ const merged: HTMLAttributes<any> = $derived({
18
+ ...props,
19
+ tabindex: 0,
20
+ role: "button",
21
+ "data-open": popover.open,
22
+ "data-popover": popover.node?.popover,
23
+ onclick: (ev) => {
24
+ props.onclick?.(ev);
25
+ popover.toggle(undefined, ev.currentTarget);
26
+ },
27
+ });
10
28
  </script>
11
29
 
12
- <div
13
- {...props}
14
- role="button"
15
- tabindex="0"
16
- data-slot="autocomplete-trigger"
17
- data-open={popover.open}
18
- data-popover={popover.node?.popover}
19
- class={autocompleteVariants().trigger({
20
- class: [
21
- props?.class?.toString(),
22
- "data-[open=true]:[[data-popover=''],[data-popover='auto']]:pointer-events-none",
23
- ],
24
- })}
25
- onclick={(ev) => popover.toggle(undefined, ev.currentTarget)}
26
- >
27
- {@render children?.()}
28
- </div>
30
+ {#if child}
31
+ {@render child({ props: merged, ctx })}
32
+ {:else}
33
+ <div
34
+ {...merged}
35
+ data-slot="autocomplete-trigger"
36
+ class={autocompleteVariants().trigger({
37
+ ...ctx.heroui,
38
+ class: [
39
+ props?.class?.toString(),
40
+ "data-[open=true]:[[data-popover=''],[data-popover='auto']]:pointer-events-none",
41
+ ],
42
+ })}
43
+ >
44
+ {#if children}
45
+ {@render children()}
46
+ {:else}
47
+ <AutocompleteValue placeholder={props.placeholder ?? undefined} />
48
+ <AutocompleteIndicator />
49
+ <AutocompleteClearButton />
50
+ {/if}
51
+ </div>
52
+ {/if}
@@ -1,6 +1,12 @@
1
1
  import type { HTMLAttributes } from "svelte/elements";
2
- interface Props extends HTMLAttributes<HTMLDivElement> {
3
- }
2
+ import { AutocompleteContext } from "../../index.js";
3
+ import type { Snippet } from "svelte";
4
+ type Props = HTMLAttributes<HTMLDivElement> & {
5
+ child?: Snippet<[{
6
+ props: HTMLAttributes<any>;
7
+ ctx: AutocompleteContext;
8
+ }]>;
9
+ };
4
10
  declare const AutocompleteTrigger: import("svelte").Component<Props, {}, "">;
5
11
  type AutocompleteTrigger = ReturnType<typeof AutocompleteTrigger>;
6
12
  export default AutocompleteTrigger;
@@ -1,11 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
- import {
4
- Popover,
5
- AutocompleteContext,
6
- type AutocompleteOpts,
7
- } from "../../index.js";
3
+ import { Popover, AutocompleteContext, type AutocompleteOpts } from "../../index.js";
8
4
  import { box } from "svelte-utils";
5
+ import { autocompleteVariants } from "@heroui/styles";
9
6
 
10
7
  type Props = HTMLAttributes<HTMLElement> &
11
8
  Partial<AutocompleteOpts> & {
@@ -48,5 +45,14 @@
48
45
  </script>
49
46
 
50
47
  <Popover {offset} {placement}>
51
- {@render props.children?.()}
48
+ <div
49
+ {...props}
50
+ class={autocompleteVariants().base({
51
+ fullWidth,
52
+ variant,
53
+ class: props.class?.toString(),
54
+ })}
55
+ >
56
+ {@render props.children?.()}
57
+ </div>
52
58
  </Popover>
@@ -1,12 +1,12 @@
1
1
  import type { AutocompleteVariants } from "@heroui/styles";
2
- import { Context, type Box, type Getter } from "svelte-utils";
3
- import { ListBoxContext, PopoverContext, type ListBoxOpts, type PopoverContextOpts } from "../../index.js";
2
+ import { Context, type Box, type Getter, PopoverState } from "svelte-utils";
3
+ import { ListBoxContext, type ListBoxOpts, type PopoverContextOpts } from "../../index.js";
4
4
  export type AutocompleteOpts = ListBoxOpts & AutocompleteVariants & PopoverContextOpts & {
5
5
  invalid?: boolean;
6
6
  };
7
7
  export declare class AutocompleteContext extends Context {
8
8
  opts: AutocompleteOpts;
9
- popoverCtx: PopoverContext;
9
+ popover: PopoverState;
10
10
  listboxCtx: ListBoxContext;
11
11
  constructor(opts: Getter<AutocompleteOpts>, selected: Box<string[]>);
12
12
  autoCloseOnFocusLost(): () => void;
@@ -1,34 +1,33 @@
1
- import { Context, isEventTargetInAny, watch } from "svelte-utils";
2
- import { ListBoxContext, PopoverContext } from "../../index.js";
1
+ import { Context, isEventTargetInAny, watch, PopoverState } from "svelte-utils";
2
+ import { ListBoxContext } from "../../index.js";
3
3
  export class AutocompleteContext extends Context {
4
4
  opts;
5
- popoverCtx;
5
+ popover = new PopoverState();
6
6
  listboxCtx;
7
7
  constructor(opts, selected) {
8
8
  super();
9
9
  this.opts = $derived.by(opts);
10
- this.popoverCtx = new PopoverContext(opts);
11
10
  this.listboxCtx = new ListBoxContext(opts, selected);
12
11
  this.autoCloseOnFocusLost();
13
12
  this.autoCloseOnSingleSelect();
14
13
  }
15
14
  autoCloseOnFocusLost() {
16
15
  const handleWindowClick = (ev) => {
17
- if (!this.popoverCtx.popover.node?.matches(":popover-open"))
16
+ if (!this.popover.node?.matches(":popover-open"))
18
17
  return;
19
- if (isEventTargetInAny(ev, this.popoverCtx.popover.anchor, this.popoverCtx.popover.node)) {
18
+ if (isEventTargetInAny(ev, this.popover.anchor, this.popover.node)) {
20
19
  return;
21
20
  }
22
21
  this.close();
23
22
  };
24
23
  const handleEscapeKey = (ev) => {
25
- const focused = this.popoverCtx.popover.node?.matches(":focus-within") || this.popoverCtx.popover.anchor?.matches(":focus-within");
24
+ const focused = this.popover.node?.matches(":focus-within") || this.popover.anchor?.matches(":focus-within");
26
25
  if (ev.code !== "Escape" || !focused)
27
26
  return;
28
27
  ev.preventDefault();
29
28
  ev.stopImmediatePropagation();
30
29
  this.close();
31
- this.popoverCtx.popover.anchor?.focus();
30
+ this.popover.anchor?.focus();
32
31
  };
33
32
  window.addEventListener("click", handleWindowClick);
34
33
  window.addEventListener("keydown", handleEscapeKey);
@@ -45,13 +44,13 @@ export class AutocompleteContext extends Context {
45
44
  });
46
45
  }
47
46
  close() {
48
- this.popoverCtx.popover.hide();
47
+ this.popover.hide();
49
48
  }
50
49
  open(source) {
51
- this.popoverCtx.popover.node?.showPopover({ source });
50
+ this.popover.node?.showPopover({ source });
52
51
  }
53
52
  toggle(source) {
54
- this.popoverCtx.popover.node?.togglePopover({ source });
53
+ this.popover.node?.togglePopover({ source });
55
54
  }
56
55
  get props() {
57
56
  return {
@@ -2,6 +2,7 @@
2
2
  import { checkboxVariants } from "@heroui/styles";
3
3
  import type { HTMLLabelAttributes } from "svelte/elements";
4
4
  import { InputContext, Input } from "../../index.js";
5
+ import CheckboxControl from "./checkbox-control.svelte";
5
6
 
6
7
  type Props = HTMLLabelAttributes;
7
8
 
@@ -16,11 +17,11 @@
16
17
  );
17
18
  </script>
18
19
 
19
- <label
20
- {...props}
21
- data-slot="checkbox-content"
22
- class={contentClass}
23
- >
20
+ <label {...props} data-slot="checkbox-content" class={contentClass}>
24
21
  <Input headless hidden type="checkbox" />
25
- {@render props.children?.()}
22
+ {#if props.children}
23
+ {@render props.children()}
24
+ {:else}
25
+ <CheckboxControl />
26
+ {/if}
26
27
  </label>
@@ -2,6 +2,7 @@
2
2
  import { checkboxVariants } from "@heroui/styles";
3
3
  import type { HTMLAttributes } from "svelte/elements";
4
4
  import { InputContext } from "../../index.js";
5
+ import CheckboxIndicator from "./checkbox-indicator.svelte";
5
6
 
6
7
  type Props = HTMLAttributes<HTMLSpanElement>;
7
8
 
@@ -16,10 +17,10 @@
16
17
  );
17
18
  </script>
18
19
 
19
- <span
20
- {...props}
21
- data-slot="checkbox-control"
22
- class={controlClass}
23
- >
24
- {@render props.children?.()}
20
+ <span {...props} data-slot="checkbox-control" class={controlClass}>
21
+ {#if props.children}
22
+ {@render props.children()}
23
+ {:else}
24
+ <CheckboxIndicator />
25
+ {/if}
25
26
  </span>
@@ -3,6 +3,7 @@
3
3
  import type { HTMLAttributes } from "svelte/elements";
4
4
  import { type InputOpts, InputContext } from "../../index.js";
5
5
  import { box } from "svelte-utils";
6
+ import CheckboxContent from "./checkbox-content.svelte";
6
7
 
7
8
  type Props = InputOpts &
8
9
  HTMLAttributes<HTMLDivElement> & {
@@ -56,5 +57,9 @@
56
57
  data-indeterminate={indeterminate}
57
58
  class={checkboxClass}
58
59
  >
59
- {@render props.children?.()}
60
+ {#if props.children}
61
+ {@render props.children()}
62
+ {:else}
63
+ <CheckboxContent />
64
+ {/if}
60
65
  </div>
@@ -1,5 +1,5 @@
1
1
  import { untrack } from "svelte";
2
- import { box, Context } from "svelte-utils";
2
+ import { box, boxLink, Context } from "svelte-utils";
3
3
  export class FilterContext extends Context {
4
4
  #opts;
5
5
  #query;
@@ -32,21 +32,6 @@ export class FilterContext extends Context {
32
32
  this.#query = query;
33
33
  }
34
34
  sync(box) {
35
- $effect(() => {
36
- box.current;
37
- untrack(() => {
38
- if (box.current === this.query)
39
- return;
40
- this.query = box.current;
41
- });
42
- });
43
- $effect(() => {
44
- this.query;
45
- untrack(() => {
46
- if (box.current === this.query)
47
- return;
48
- box.current = this.query;
49
- });
50
- });
35
+ boxLink(box, this.#query);
51
36
  }
52
37
  }
@@ -1,4 +1,6 @@
1
1
  import { Context, type Box, type Getter } from "svelte-utils";
2
+ import { FilterContext } from "../filter";
3
+ import type { HTMLAttributes } from "svelte/elements";
2
4
  export type ListBoxOpts = {
3
5
  disabled?: boolean;
4
6
  multiple?: boolean;
@@ -15,3 +17,21 @@ export declare class ListBoxContext extends Context {
15
17
  setSelected(value: string, checked: boolean): void;
16
18
  constructor(opts: Getter<ListBoxOpts>, selected?: Box<string[]>);
17
19
  }
20
+ export type ListBoxItemOpts = {
21
+ value: string;
22
+ disabled?: boolean;
23
+ };
24
+ export declare class ListBoxItemContext extends Context {
25
+ #private;
26
+ readonly listbox: ListBoxContext;
27
+ readonly opts: ListBoxItemOpts;
28
+ readonly filter?: FilterContext;
29
+ get selected(): boolean;
30
+ set selected(value: boolean);
31
+ get value(): string;
32
+ constructor(opts: Getter<ListBoxItemOpts>, selected?: Box<boolean>);
33
+ toggle: () => void;
34
+ get visible(): boolean;
35
+ get disabled(): boolean | undefined;
36
+ props: (props?: HTMLAttributes<HTMLDivElement>) => HTMLAttributes<HTMLDivElement>;
37
+ }
@@ -1,4 +1,6 @@
1
- import { box, boxArray, Context } from "svelte-utils";
1
+ import { box, boxArray, boxLink, Context } from "svelte-utils";
2
+ import { FilterContext } from "../filter";
3
+ import { onDestroy } from "svelte";
2
4
  export class ListBoxContext extends Context {
3
5
  #opts;
4
6
  get opts() { return this.#opts; }
@@ -23,3 +25,55 @@ export class ListBoxContext extends Context {
23
25
  this.#selected = selected;
24
26
  }
25
27
  }
28
+ export class ListBoxItemContext extends Context {
29
+ listbox;
30
+ opts;
31
+ filter;
32
+ #selected;
33
+ get selected() { return this.#selected.current; }
34
+ set selected(value) { this.#selected.current = value; }
35
+ get value() { return this.opts.value; }
36
+ constructor(opts, selected = box(false)) {
37
+ super();
38
+ this.listbox = ListBoxContext.get();
39
+ this.filter = FilterContext.getOr();
40
+ this.opts = $derived.by(opts);
41
+ this.#selected = selected;
42
+ $effect(() => this.filter?.register(this.value));
43
+ onDestroy(() => {
44
+ this.listbox.setSelected(this.value, false);
45
+ });
46
+ boxLink(box(() => this.listbox.isSelected(this.value), v => this.listbox.setSelected(this.value, v)), selected);
47
+ }
48
+ toggle = () => {
49
+ this.selected = !this.selected;
50
+ };
51
+ get visible() {
52
+ return this.filter === undefined || this.filter.matches(this.value);
53
+ }
54
+ get disabled() {
55
+ return this.opts.disabled || this.listbox.opts.disabled;
56
+ }
57
+ props = (props) => {
58
+ return {
59
+ onkeydown: ev => {
60
+ this.#onKeyDown(ev);
61
+ props?.onkeydown?.(ev);
62
+ },
63
+ onclick: ev => {
64
+ this.toggle();
65
+ props?.onclick?.(ev);
66
+ },
67
+ "data-disabled": this.disabled,
68
+ "aria-disabled": this.disabled,
69
+ tabindex: 0,
70
+ role: "checkbox"
71
+ };
72
+ };
73
+ #onKeyDown(ev) {
74
+ if (ev.code === "Space" ||
75
+ (ev.code === "Enter" && ev.target === ev.currentTarget)) {
76
+ this.toggle();
77
+ }
78
+ }
79
+ }
@@ -1,21 +1,15 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
3
  import { listboxItemVariants } from "@heroui/styles";
4
- import { ListBoxContext } from "./index.svelte";
4
+ import { ListBoxItemContext } from "./index.svelte";
5
5
 
6
6
  let { ...props }: HTMLAttributes<HTMLDivElement> = $props();
7
7
 
8
- let node = $state<HTMLElement>();
9
- const ctx = ListBoxContext.get();
10
- const value = $derived(
11
- node?.closest(".list-box-item")?.getAttribute("data-value"),
12
- );
13
- const selected = $derived(value && ctx.isSelected(value));
8
+ const ctx = ListBoxItemContext.get();
14
9
  </script>
15
10
 
16
11
  <div
17
12
  {...props}
18
- bind:this={node}
19
13
  data-slot="list-box-item-indicator"
20
14
  class={listboxItemVariants().indicator({ class: props.class?.toString() })}
21
15
  >
@@ -26,7 +20,7 @@
26
20
  role="presentation"
27
21
  stroke="currentColor"
28
22
  stroke-dasharray={22}
29
- stroke-dashoffset={selected ? 44 : 66}
23
+ stroke-dashoffset={ctx.selected ? 44 : 66}
30
24
  stroke-linecap="round"
31
25
  stroke-linejoin="round"
32
26
  stroke-width={2}
@@ -1,78 +1,53 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
3
  import { listboxItemVariants } from "@heroui/styles";
4
- import { ListBoxContext } from "../../index.js";
5
- import { FilterContext } from "../filter/index.svelte";
6
- import { watch } from "svelte-utils";
4
+ import { ListBoxItemContext } from "../../index.js";
5
+ import { box } from "svelte-utils";
6
+ import type { Snippet } from "svelte";
7
7
 
8
8
  let {
9
- value,
9
+ value = crypto.randomUUID(),
10
10
  disabled,
11
11
  selected = $bindable(),
12
+ child,
12
13
  ...props
13
14
  }: HTMLAttributes<HTMLDivElement> & {
14
- value: string;
15
+ value?: string;
15
16
  selected?: boolean;
16
17
  disabled?: boolean;
18
+ child?: Snippet<[ListBoxItemContext]>;
17
19
  } = $props();
18
20
 
19
- const filter = FilterContext.getOr();
20
- const ctx = ListBoxContext.get();
21
- const hidden = $derived(filter && !filter.matches(value));
22
-
23
- watch(
24
- () => selected,
25
- (curr) => {
26
- if (curr === ctx.isSelected(value)) return;
27
- ctx.setSelected(value, curr ?? ctx.isSelected(value));
28
- },
29
- );
30
-
31
- watch(
32
- () => ctx.isSelected(value),
33
- (curr) => {
34
- if (curr === selected) return;
35
- selected = curr;
36
- },
21
+ const ctx = new ListBoxItemContext(
22
+ () => ({ value, disabled }),
23
+ box(
24
+ () => !!selected,
25
+ (v) => (selected = v),
26
+ ),
37
27
  );
38
-
39
- $effect(() => () => ctx.setSelected(value, false));
40
- $effect(() => filter?.register(value));
41
28
  </script>
42
29
 
43
- {#if !hidden}
30
+ {#if child}
31
+ {@render child(ctx)}
32
+ {:else if ctx.visible}
44
33
  <div
45
- {...props}
46
- onkeydown={(ev) => {
47
- if (
48
- ev.code === "Space" ||
49
- (ev.code === "Enter" && ev.target === ev.currentTarget)
50
- ) {
51
- ev.preventDefault();
52
- ctx.setSelected(value, !selected);
53
- }
54
- }}
55
- onclick={() => ctx.setSelected(value, !selected)}
56
- role="checkbox"
57
- tabindex="0"
58
- data-value={value}
59
- data-disabled={ctx.opts.disabled ?? disabled}
34
+ {...ctx.props(props)}
60
35
  data-slot="list-box-item"
61
36
  class={listboxItemVariants().item({ class: props.class?.toString() })}
62
37
  >
63
- {#if ctx.opts.name}
38
+ {#if ctx.listbox.opts.name}
64
39
  <input
65
40
  {@attach (node) => {
66
41
  const form = node.form;
67
42
  if (!form) return;
68
- const reset = () => ctx.setSelected(value, false);
43
+ const reset = () => (ctx.selected = false);
69
44
  form.addEventListener("reset", reset);
70
45
  return () => form.removeEventListener("reset", reset);
71
46
  }}
72
- checked={ctx.isSelected(value)}
73
- disabled={ctx.opts.disabled ?? disabled}
74
- required={ctx.opts.required}
75
- name={ctx.opts.name}
47
+ checked={ctx.selected}
48
+ disabled={ctx.disabled}
49
+ required={ctx.listbox.opts.required}
50
+ name={ctx.listbox.opts.name}
76
51
  type={"checkbox"}
77
52
  {value}
78
53
  hidden
@@ -1,8 +1,11 @@
1
1
  import type { HTMLAttributes } from "svelte/elements";
2
+ import { ListBoxItemContext } from "../../index.js";
3
+ import type { Snippet } from "svelte";
2
4
  type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
3
- value: string;
5
+ value?: string;
4
6
  selected?: boolean;
5
7
  disabled?: boolean;
8
+ child?: Snippet<[ListBoxItemContext]>;
6
9
  };
7
10
  declare const ListBoxItem: import("svelte").Component<$$ComponentProps, {}, "selected">;
8
11
  type ListBoxItem = ReturnType<typeof ListBoxItem>;
@@ -9,11 +9,10 @@
9
9
  selected?: string[];
10
10
  };
11
11
 
12
- const id = $props.id();
13
12
  let {
14
13
  multiple,
15
14
  selected = $bindable([]),
16
- name = id,
15
+ name,
17
16
  disabled,
18
17
  required,
19
18
  ...props
@@ -1,23 +1,32 @@
1
1
  <script lang="ts">
2
+ import type { HTMLAttributes } from "svelte/elements";
2
3
  import Button from "../button/button.svelte";
3
4
  import { ModalContext } from "./index.svelte";
4
- import type { ComponentProps } from "svelte";
5
+ import type { ComponentProps, Snippet } from "svelte";
5
6
 
6
7
  const {
7
8
  action = "show",
9
+ child,
8
10
  ...props
9
11
  }: ComponentProps<typeof Button> & {
10
12
  action?: "show" | "close";
13
+ child?: Snippet<[{ props: HTMLAttributes<any> }]>;
11
14
  } = $props();
12
15
 
13
16
  const ctx = ModalContext.get();
17
+ const merged: HTMLAttributes<any> = $derived({
18
+ ...props,
19
+ onclick: (ev) => {
20
+ ctx.dialog.toggle?.();
21
+ props.onclick?.(ev);
22
+ },
23
+ });
14
24
  </script>
15
25
 
16
- <Button
17
- {...props}
18
- type="button"
19
- command={action === "show" ? "show-modal" : "close"}
20
- commandfor={ctx.dialog.nodeId}
21
- >
22
- {@render props.children?.()}
23
- </Button>
26
+ {#if child}
27
+ {@render child({ props: merged })}
28
+ {:else}
29
+ <Button {...merged} type="button">
30
+ {@render props.children?.()}
31
+ </Button>
32
+ {/if}
@@ -1,7 +1,11 @@
1
+ import type { HTMLAttributes } from "svelte/elements";
1
2
  import Button from "../button/button.svelte";
2
- import type { ComponentProps } from "svelte";
3
+ import type { ComponentProps, Snippet } from "svelte";
3
4
  type $$ComponentProps = ComponentProps<typeof Button> & {
4
5
  action?: "show" | "close";
6
+ child?: Snippet<[{
7
+ props: HTMLAttributes<any>;
8
+ }]>;
5
9
  };
6
10
  declare const ModalTrigger: import("svelte").Component<$$ComponentProps, {}, "">;
7
11
  type ModalTrigger = ReturnType<typeof ModalTrigger>;
@@ -2,6 +2,10 @@
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
3
  import PaginationState from "./index.svelte";
4
4
  import { paginationVariants } from "@heroui/styles";
5
+ import PaginationItem from "./pagination-item.svelte";
6
+ import PaginationPrevious from "./pagination-previous.svelte";
7
+ import PaginationNext from "./pagination-next.svelte";
8
+ import PaginationLink from "./pagination-link.svelte";
5
9
 
6
10
  const props: HTMLAttributes<HTMLUListElement> = $props();
7
11
  const pagination = PaginationState.get();
@@ -13,5 +17,17 @@
13
17
  class: props.class?.toString(),
14
18
  })}
15
19
  >
16
- {@render props.children?.()}
20
+ {#if props.children}
21
+ {@render props.children()}
22
+ {:else}
23
+ <PaginationItem>
24
+ <PaginationPrevious />
25
+ </PaginationItem>
26
+ <PaginationItem>
27
+ <PaginationLink disabled={pagination.total === 0} page={pagination.page} />
28
+ </PaginationItem>
29
+ <PaginationItem>
30
+ <PaginationNext />
31
+ </PaginationItem>
32
+ {/if}
17
33
  </ul>
@@ -22,5 +22,9 @@
22
22
  class: props.class?.toString(),
23
23
  })}
24
24
  >
25
- {@render props.children?.()}
25
+ {#if props.children}
26
+ {@render props.children()}
27
+ {:else}
28
+ {page}
29
+ {/if}
26
30
  </button>
@@ -2,6 +2,7 @@
2
2
  import type { HTMLButtonAttributes } from "svelte/elements";
3
3
  import PaginationState from "./index.svelte";
4
4
  import { paginationVariants } from "@heroui/styles";
5
+ import { PaginationNextIcon } from ".";
5
6
 
6
7
  const props: HTMLButtonAttributes = $props();
7
8
  const pagination = PaginationState.get();
@@ -19,5 +20,10 @@
19
20
  class: ["pagination__link--nav"],
20
21
  })}
21
22
  >
22
- {@render props.children?.()}
23
+ {#if props.children}
24
+ {@render props.children()}
25
+ {:else}
26
+ Next
27
+ <PaginationNextIcon />
28
+ {/if}
23
29
  </button>
@@ -2,6 +2,7 @@
2
2
  import type { HTMLButtonAttributes } from "svelte/elements";
3
3
  import PaginationState from "./index.svelte";
4
4
  import { paginationVariants } from "@heroui/styles";
5
+ import PaginationPreviousIcon from "./pagination-previous-icon.svelte";
5
6
 
6
7
  const props: HTMLButtonAttributes = $props();
7
8
  const pagination = PaginationState.get();
@@ -19,5 +20,10 @@
19
20
  class: ["pagination__link--nav"],
20
21
  })}
21
22
  >
22
- {@render props.children?.()}
23
+ {#if props.children}
24
+ {@render props.children()}
25
+ {:else}
26
+ <PaginationPreviousIcon />
27
+ Prev
28
+ {/if}
23
29
  </button>
@@ -19,5 +19,11 @@
19
19
  class: props.class?.toString(),
20
20
  })}
21
21
  >
22
- {@render children?.(pagination)}
22
+ {#if children}
23
+ {@render children(pagination)}
24
+ {:else if pagination.total === 0}
25
+ Showing empty
26
+ {:else}
27
+ Showing {pagination.start} ~ {pagination.end} of {pagination.total}
28
+ {/if}
23
29
  </div>
@@ -4,6 +4,8 @@
4
4
  import type { HTMLAttributes } from "svelte/elements";
5
5
  import PaginationState from "./index.svelte";
6
6
  import { box } from "svelte-utils";
7
+ import PaginationSummary from "./pagination-summary.svelte";
8
+ import PaginationContent from "./pagination-content.svelte";
7
9
 
8
10
  let {
9
11
  page = $bindable(1),
@@ -36,5 +38,10 @@
36
38
  class: props.class?.toString(),
37
39
  })}
38
40
  >
39
- {@render props.children?.()}
41
+ {#if props.children}
42
+ {@render props.children()}
43
+ {:else}
44
+ <PaginationSummary />
45
+ <PaginationContent />
46
+ {/if}
40
47
  </div>
@@ -1,4 +1,4 @@
1
- import { Context, PopoverState, type Box, type Getter } from "svelte-utils";
1
+ import { Context, PopoverState, type Box, type Getter } from "@adriansyah/svelte-utils";
2
2
  export type PopoverContextOpts = {
3
3
  placement?: "bottom" | "top" | "left" | "right";
4
4
  offset?: number;
@@ -1,4 +1,4 @@
1
- import { Context, getPopoverArea, PopoverState } from "svelte-utils";
1
+ import { Context, getPopoverArea, PopoverState } from "@adriansyah/svelte-utils";
2
2
  export class PopoverContext extends Context {
3
3
  get open() { return this.popover.open; }
4
4
  set open(open) { this.popover.open = open; }
@@ -1,17 +1,34 @@
1
1
  <script lang="ts">
2
- import type { ComponentProps } from "svelte";
2
+ import type { ComponentProps, Snippet } from "svelte";
3
3
  import Button from "../button/button.svelte";
4
4
  import { PopoverContext } from "./index.svelte";
5
+ import type { PopoverState } from "@adriansyah/svelte-utils";
5
6
 
6
- const props: ComponentProps<typeof Button> = $props();
7
+ type Props = ComponentProps<typeof Button> & {
8
+ child?: Snippet<
9
+ [{ props: ComponentProps<typeof Button>; popover: PopoverState }]
10
+ >;
11
+ };
12
+
13
+ const { child, ...props }: Props = $props();
7
14
 
8
15
  const ctx = PopoverContext.get();
16
+ const merged: ComponentProps<typeof Button> = $derived({
17
+ ...props,
18
+ ...{
19
+ type: "button",
20
+ command: "toggle-popover",
21
+ commandfor: ctx.popover.nodeId,
22
+ pressed: ctx.popover.open,
23
+ },
24
+ });
9
25
  </script>
10
26
 
11
- <Button
12
- {...props}
13
- type="button"
14
- command="toggle-popover"
15
- commandfor={ctx.popover.nodeId}
16
- pressed={ctx.popover.open}
17
- />
27
+ {#if child}
28
+ {@render child({
29
+ props: merged,
30
+ popover: ctx.popover,
31
+ })}
32
+ {:else}
33
+ <Button {...merged} />
34
+ {/if}
@@ -1,9 +1,14 @@
1
- declare const PopoverTrigger: import("svelte").Component<{
2
- focused?: boolean;
3
- hovered?: boolean;
4
- pending?: boolean;
5
- pressed?: boolean;
6
- disabled?: boolean;
7
- } & import("@heroui/styles").ButtonVariants & import("svelte/elements").HTMLButtonAttributes, {}, "">;
1
+ import type { ComponentProps, Snippet } from "svelte";
2
+ import Button from "../button/button.svelte";
3
+ import type { PopoverState } from "@adriansyah/svelte-utils";
4
+ type Props = ComponentProps<typeof Button> & {
5
+ child?: Snippet<[
6
+ {
7
+ props: ComponentProps<typeof Button>;
8
+ popover: PopoverState;
9
+ }
10
+ ]>;
11
+ };
12
+ declare const PopoverTrigger: import("svelte").Component<Props, {}, "">;
8
13
  type PopoverTrigger = ReturnType<typeof PopoverTrigger>;
9
14
  export default PopoverTrigger;
@@ -17,7 +17,7 @@
17
17
  children,
18
18
  }: Partial<Props> = $props();
19
19
 
20
- export const context = PopoverContext.getOr([
20
+ new PopoverContext(
21
21
  () => ({
22
22
  fallbackAnchor,
23
23
  offset,
@@ -27,7 +27,7 @@
27
27
  () => open,
28
28
  (v) => (open = v),
29
29
  ),
30
- ]);
30
+ );
31
31
  </script>
32
32
 
33
33
  {@render children?.()}
@@ -1,11 +1,9 @@
1
- import { PopoverContext, type PopoverContextOpts } from "./index.svelte";
1
+ import { type PopoverContextOpts } from "./index.svelte";
2
2
  import type { Snippet } from "svelte";
3
3
  declare const Popover: import("svelte").Component<Partial<Omit<PopoverContextOpts, "open" | "fallbackAnchor"> & {
4
4
  open?: boolean;
5
5
  fallbackAnchor?: HTMLElement;
6
6
  children?: Snippet;
7
- }>, {
8
- context: PopoverContext;
9
- }, "open">;
7
+ }>, {}, "open">;
10
8
  type Popover = ReturnType<typeof Popover>;
11
9
  export default Popover;
@@ -34,7 +34,7 @@
34
34
 
35
35
  const filter = FilterContext.getOr();
36
36
  const empty = $derived(value === undefined || value === "");
37
- InputContext.getOr([
37
+ new InputContext(
38
38
  () => ({
39
39
  disabled,
40
40
  fullWidth,
@@ -48,13 +48,14 @@
48
48
  () => value,
49
49
  (v) => (value = v),
50
50
  ),
51
- ]);
51
+ );
52
52
 
53
53
  watch(
54
54
  () => value ?? "",
55
55
  (currentValue) => {
56
+ if (currentValue === value) return;
56
57
  const timeout = setTimeout(
57
- () => (debounced = currentValue),
58
+ () => (debounced = String(currentValue)),
58
59
  Math.max(0, debounce),
59
60
  );
60
61
  return () => clearTimeout(timeout);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adriansyah/heroui-svelte",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "devDependencies": {
5
5
  "@chromatic-com/storybook": "latest",
6
6
  "@heroui/styles": "^3.2.6",
@@ -66,6 +66,6 @@
66
66
  "type": "module",
67
67
  "types": "./dist/index.d.ts",
68
68
  "dependencies": {
69
- "svelte-utils": "github:adriansyah-kadir/svelte-utils#release"
69
+ "@adriansyah/svelte-utils": "^0.0.1"
70
70
  }
71
71
  }