@websline/system-components 1.4.3 → 1.4.6

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 (52) hide show
  1. package/dist/components/atoms/checkbox/checkbox.variants.d.ts +2 -2
  2. package/dist/components/atoms/checkbox/checkbox.variants.js +1 -1
  3. package/dist/components/atoms/inputDate/InputDate.svelte +114 -0
  4. package/dist/components/atoms/inputDate/InputDate.svelte.d.ts +97 -0
  5. package/dist/components/atoms/inputDate/Picker.svelte +36 -0
  6. package/dist/components/atoms/inputDate/Picker.svelte.d.ts +21 -0
  7. package/dist/components/atoms/inputDate/input.variants.d.ts +64 -0
  8. package/dist/components/atoms/inputDate/input.variants.js +20 -0
  9. package/dist/components/atoms/radio/Radio.svelte +55 -2
  10. package/dist/components/atoms/tag/Tag.svelte +9 -7
  11. package/dist/components/atoms/tag/Tag.svelte.d.ts +8 -8
  12. package/dist/components/atoms/tag/tag.variants.d.ts +0 -9
  13. package/dist/components/atoms/tag/tag.variants.js +1 -4
  14. package/dist/components/molecules/calendar/Calendar.svelte +95 -0
  15. package/dist/components/molecules/calendar/Calendar.svelte.d.ts +42 -0
  16. package/dist/components/molecules/calendar/Container.svelte +25 -0
  17. package/dist/components/molecules/calendar/Container.svelte.d.ts +25 -0
  18. package/dist/components/molecules/calendar/DayCell.svelte +47 -0
  19. package/dist/components/molecules/calendar/RootContext.svelte +28 -0
  20. package/dist/components/molecules/calendar/RootContext.svelte.d.ts +21 -0
  21. package/dist/components/molecules/calendar/WeekRow.svelte +65 -0
  22. package/dist/components/molecules/calendar/Weekdays.svelte +27 -0
  23. package/dist/components/molecules/calendar/Weekdays.svelte.d.ts +17 -0
  24. package/dist/components/molecules/calendar/calendar.variant.d.ts +79 -0
  25. package/dist/components/molecules/calendar/calendar.variant.js +36 -0
  26. package/dist/components/molecules/calendar/index.d.ts +8 -0
  27. package/dist/components/molecules/calendar/index.js +10 -0
  28. package/dist/components/molecules/formField/FormField.svelte +1 -1
  29. package/dist/components/molecules/formField/FormField.svelte.d.ts +2 -2
  30. package/dist/components/molecules/formField/formField.variants.d.ts +12 -12
  31. package/dist/components/molecules/formField/formField.variants.js +21 -5
  32. package/dist/components/molecules/richTextEditor/RichTextEditor.svelte +9 -4
  33. package/dist/components/molecules/selectorCard/SelectorCard.svelte +8 -2
  34. package/dist/components/molecules/selectorCard/SelectorCard.svelte.d.ts +2 -2
  35. package/dist/components/molecules/tagSelector/TagSelector.svelte +12 -0
  36. package/dist/components/molecules/tagSelector/TagSelector.svelte.d.ts +16 -0
  37. package/dist/components/molecules/tagSelector/ValueList.svelte +12 -2
  38. package/dist/components/molecules/tagSelector/ValueList.svelte.d.ts +4 -0
  39. package/dist/components/molecules/tagSelector/tagSelector.variants.js +2 -2
  40. package/dist/components/organisms/tooltip/Content.svelte +51 -0
  41. package/dist/components/organisms/tooltip/Content.svelte.d.ts +57 -0
  42. package/dist/components/organisms/tooltip/Tooltip.svelte +15 -0
  43. package/dist/components/organisms/tooltip/Tooltip.svelte.d.ts +17 -0
  44. package/dist/components/organisms/tooltip/Trigger.svelte +13 -0
  45. package/dist/components/organisms/tooltip/Trigger.svelte.d.ts +17 -0
  46. package/dist/components/organisms/tooltip/index.d.ts +4 -0
  47. package/dist/components/organisms/tooltip/index.js +5 -0
  48. package/dist/components/organisms/tooltip/tooltip.variant.d.ts +24 -0
  49. package/dist/components/organisms/tooltip/tooltip.variant.js +20 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.js +3 -0
  52. package/package.json +25 -25
@@ -5,7 +5,7 @@ export const checkboxVariants: import("tailwind-variants").TVReturnType<{
5
5
  error: {
6
6
  true: string;
7
7
  };
8
- }, undefined, "size-4 cursor-pointer rounded border border-current bg-transparent bg-none text-neutral-900 ring-0 ring-transparent ring-offset-transparent outline-transparent duration-300 after:block after:size-full checked:bg-none checked:after:bg-current focus:outline-1 focus:outline-offset-1 focus:outline-blue-300 dark:text-white", {
8
+ }, undefined, "size-4 cursor-pointer rounded-xs border border-neutral-300 bg-transparent bg-none text-neutral-900 ring-0 ring-transparent ring-offset-transparent outline-transparent duration-300 after:block after:size-full checked:bg-none checked:after:bg-current focus:outline-1 focus:outline-offset-1 focus:outline-blue-300 dark:border-neutral-600 dark:text-white", {
9
9
  disabled: {
10
10
  true: string;
11
11
  };
@@ -19,4 +19,4 @@ export const checkboxVariants: import("tailwind-variants").TVReturnType<{
19
19
  error: {
20
20
  true: string;
21
21
  };
22
- }, undefined, "size-4 cursor-pointer rounded border border-current bg-transparent bg-none text-neutral-900 ring-0 ring-transparent ring-offset-transparent outline-transparent duration-300 after:block after:size-full checked:bg-none checked:after:bg-current focus:outline-1 focus:outline-offset-1 focus:outline-blue-300 dark:text-white", unknown, unknown, undefined>>;
22
+ }, undefined, "size-4 cursor-pointer rounded-xs border border-neutral-300 bg-transparent bg-none text-neutral-900 ring-0 ring-transparent ring-offset-transparent outline-transparent duration-300 after:block after:size-full checked:bg-none checked:after:bg-current focus:outline-1 focus:outline-offset-1 focus:outline-blue-300 dark:border-neutral-600 dark:text-white", unknown, unknown, undefined>>;
@@ -1,7 +1,7 @@
1
1
  import { tv } from "../../../utils/tailwind.js";
2
2
 
3
3
  const checkboxVariants = tv({
4
- base: "size-4 cursor-pointer rounded border border-current bg-transparent bg-none text-neutral-900 ring-0 ring-transparent ring-offset-transparent outline-transparent duration-300 after:block after:size-full checked:bg-none checked:after:bg-current focus:outline-1 focus:outline-offset-1 focus:outline-blue-300 dark:text-white",
4
+ base: "size-4 cursor-pointer rounded-xs border border-neutral-300 bg-transparent bg-none text-neutral-900 ring-0 ring-transparent ring-offset-transparent outline-transparent duration-300 after:block after:size-full checked:bg-none checked:after:bg-current focus:outline-1 focus:outline-offset-1 focus:outline-blue-300 dark:border-neutral-600 dark:text-white",
5
5
  variants: {
6
6
  disabled: {
7
7
  true: "cursor-not-allowed",
@@ -0,0 +1,114 @@
1
+ <script>
2
+ import { Popover } from "bits-ui";
3
+ import { getContext } from "svelte";
4
+ import { IconButton } from "../../../index.js";
5
+ import Picker from "./Picker.svelte";
6
+ import { inputVariants } from "./input.variants.js";
7
+
8
+ /**
9
+ * @typedef {Object} Props
10
+ * @property {string|import("svelte").SvelteComponent|Function} [adornmentStart=""] Content to display at the start of the input (e.g., icon or text)
11
+ * @property {import("svelte").SvelteComponent} [children] Additional content to render inside the input component
12
+ * @property {string} [class=""] Additional CSS classes to apply to the component
13
+ * @property {boolean} [disabled] Whether the input is disabled
14
+ * @property {boolean} [error] Whether the input has an error state
15
+ * @property {string} [id] The ID of the input element
16
+ * @property {string} [name] The name of the input, used for form submission
17
+ * @property {string} [placeholder=""] Placeholder text for the input
18
+ * @property {boolean} [readonly=false] Whether the input is read-only
19
+ * @property {boolean} [required] Whether the input is required
20
+ * @property {string} [value=""] The value of the input, bound to the component
21
+ */
22
+
23
+ /** @type {Props} */
24
+ let {
25
+ adornmentStart = "",
26
+ children,
27
+ class: className = "",
28
+ disabled,
29
+ error,
30
+ id,
31
+ name,
32
+ placeholder = "",
33
+ readonly = false,
34
+ required,
35
+ value = $bindable(),
36
+ // TODO
37
+ preventScroll = false,
38
+ portalDisabled = true,
39
+ portalTarget = "body",
40
+ side = "bottom",
41
+ sideOffset = 8,
42
+ ...rest
43
+ } = $props();
44
+
45
+ let store = getContext("form-field-store") ?? null;
46
+
47
+ let localValues = $derived.by(() => {
48
+ const storeValues = typeof store === "function" ? store() : {};
49
+
50
+ return {
51
+ disabled: disabled ?? storeValues.disabled ?? false,
52
+ error: error ?? storeValues.error ?? false,
53
+ id: id ?? storeValues.id ?? "",
54
+ required: required ?? storeValues.required ?? false,
55
+ };
56
+ });
57
+
58
+ let styles = $derived(
59
+ inputVariants({
60
+ disabled: localValues.disabled,
61
+ error: localValues.error,
62
+ }),
63
+ );
64
+ </script>
65
+
66
+ <Popover.Root>
67
+ <div class={styles.base({ class: className })}>
68
+ {#if adornmentStart}
69
+ <div class={styles.adornmentStart()}>
70
+ {#if typeof adornmentStart === "function"}
71
+ {@render adornmentStart()}
72
+ {:else}
73
+ {adornmentStart}
74
+ {/if}
75
+ </div>
76
+ {/if}
77
+
78
+ {#if children}
79
+ <!-- The date picker -->
80
+ <Picker
81
+ {children}
82
+ {preventScroll}
83
+ {portalDisabled}
84
+ {portalTarget}
85
+ {side}
86
+ {sideOffset} />
87
+ {/if}
88
+
89
+ <input
90
+ class={styles.input()}
91
+ disabled={localValues.disabled}
92
+ id={localValues.id}
93
+ {name}
94
+ {placeholder}
95
+ {readonly}
96
+ required={localValues.required}
97
+ {...rest}
98
+ bind:value />
99
+
100
+ <div class={styles.adornmentEnd()}>
101
+ <Popover.Trigger>
102
+ {#snippet child({ props })}
103
+ <IconButton
104
+ color="transparent"
105
+ icon="calendar"
106
+ iconSize={24}
107
+ shape="square"
108
+ size="small"
109
+ {...props} />
110
+ {/snippet}
111
+ </Popover.Trigger>
112
+ </div>
113
+ </div>
114
+ </Popover.Root>
@@ -0,0 +1,97 @@
1
+ export default InputDate;
2
+ type InputDate = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<Props>): void;
5
+ };
6
+ declare const InputDate: import("svelte").Component<{
7
+ /**
8
+ * Content to display at the start of the input (e.g., icon or text)
9
+ */
10
+ adornmentStart?: string | import("svelte").SvelteComponent | Function;
11
+ /**
12
+ * Additional content to render inside the input component
13
+ */
14
+ children?: import("svelte").SvelteComponent;
15
+ /**
16
+ * Additional CSS classes to apply to the component
17
+ */
18
+ class?: string;
19
+ /**
20
+ * Whether the input is disabled
21
+ */
22
+ disabled?: boolean;
23
+ /**
24
+ * Whether the input has an error state
25
+ */
26
+ error?: boolean;
27
+ /**
28
+ * The ID of the input element
29
+ */
30
+ id?: string;
31
+ /**
32
+ * The name of the input, used for form submission
33
+ */
34
+ name?: string;
35
+ /**
36
+ * Placeholder text for the input
37
+ */
38
+ placeholder?: string;
39
+ /**
40
+ * Whether the input is read-only
41
+ */
42
+ readonly?: boolean;
43
+ /**
44
+ * Whether the input is required
45
+ */
46
+ required?: boolean;
47
+ /**
48
+ * The value of the input, bound to the component
49
+ */
50
+ value?: string;
51
+ }, {}, "value">;
52
+ type Props = {
53
+ /**
54
+ * Content to display at the start of the input (e.g., icon or text)
55
+ */
56
+ adornmentStart?: string | import("svelte").SvelteComponent | Function;
57
+ /**
58
+ * Additional content to render inside the input component
59
+ */
60
+ children?: import("svelte").SvelteComponent;
61
+ /**
62
+ * Additional CSS classes to apply to the component
63
+ */
64
+ class?: string;
65
+ /**
66
+ * Whether the input is disabled
67
+ */
68
+ disabled?: boolean;
69
+ /**
70
+ * Whether the input has an error state
71
+ */
72
+ error?: boolean;
73
+ /**
74
+ * The ID of the input element
75
+ */
76
+ id?: string;
77
+ /**
78
+ * The name of the input, used for form submission
79
+ */
80
+ name?: string;
81
+ /**
82
+ * Placeholder text for the input
83
+ */
84
+ placeholder?: string;
85
+ /**
86
+ * Whether the input is read-only
87
+ */
88
+ readonly?: boolean;
89
+ /**
90
+ * Whether the input is required
91
+ */
92
+ required?: boolean;
93
+ /**
94
+ * The value of the input, bound to the component
95
+ */
96
+ value?: string;
97
+ };
@@ -0,0 +1,36 @@
1
+ <script>
2
+ import { Popover } from "bits-ui";
3
+ import { quintOut } from "svelte/easing";
4
+ import { scale } from "svelte/transition";
5
+
6
+ let {
7
+ children,
8
+ preventScroll = false,
9
+ portalDisabled = true,
10
+ portalTarget = "body",
11
+ side = "bottom",
12
+ sideOffset = 8,
13
+ ...rest
14
+ } = $props();
15
+ </script>
16
+
17
+ <Popover.Portal disabled={portalDisabled} to={portalTarget}>
18
+ <Popover.Content
19
+ align="end"
20
+ alignOffset={0}
21
+ forceMount
22
+ {preventScroll}
23
+ {side}
24
+ {sideOffset}
25
+ {...rest}>
26
+ {#snippet child({ open, props, wrapperProps })}
27
+ {#if open}
28
+ <div {...wrapperProps}>
29
+ <div {...props} in:scale={{ duration: 300, easing: quintOut, start: 0.75 }}>
30
+ {@render children()}
31
+ </div>
32
+ </div>
33
+ {/if}
34
+ {/snippet}
35
+ </Popover.Content>
36
+ </Popover.Portal>
@@ -0,0 +1,21 @@
1
+ export default Picker;
2
+ type Picker = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const Picker: import("svelte").Component<{
7
+ children: any;
8
+ preventScroll?: boolean;
9
+ portalDisabled?: boolean;
10
+ portalTarget?: string;
11
+ side?: string;
12
+ sideOffset?: number;
13
+ } & Record<string, any>, {}, "">;
14
+ type $$ComponentProps = {
15
+ children: any;
16
+ preventScroll?: boolean;
17
+ portalDisabled?: boolean;
18
+ portalTarget?: string;
19
+ side?: string;
20
+ sideOffset?: number;
21
+ } & Record<string, any>;
@@ -0,0 +1,64 @@
1
+ export const inputVariants: import("tailwind-variants").TVReturnType<{
2
+ disabled: {
3
+ true: {
4
+ input: string;
5
+ };
6
+ };
7
+ }, {
8
+ adornmentStart: string;
9
+ adornmentEnd: string;
10
+ base: string;
11
+ input: string;
12
+ }, undefined, {
13
+ disabled: {
14
+ true: {
15
+ base: string;
16
+ };
17
+ };
18
+ error: {
19
+ true: {
20
+ base: string;
21
+ };
22
+ };
23
+ }, {
24
+ base: string[];
25
+ }, import("tailwind-variants").TVReturnType<{
26
+ disabled: {
27
+ true: {
28
+ base: string;
29
+ };
30
+ };
31
+ error: {
32
+ true: {
33
+ base: string;
34
+ };
35
+ };
36
+ }, {
37
+ base: string[];
38
+ }, undefined, {
39
+ disabled: {
40
+ true: {
41
+ base: string;
42
+ };
43
+ };
44
+ error: {
45
+ true: {
46
+ base: string;
47
+ };
48
+ };
49
+ }, {
50
+ base: string[];
51
+ }, import("tailwind-variants").TVReturnType<{
52
+ disabled: {
53
+ true: {
54
+ base: string;
55
+ };
56
+ };
57
+ error: {
58
+ true: {
59
+ base: string;
60
+ };
61
+ };
62
+ }, {
63
+ base: string[];
64
+ }, undefined, unknown, unknown, undefined>>>;
@@ -0,0 +1,20 @@
1
+ import { inputBaseVariant, tv } from "../../../utils/tailwind.js";
2
+
3
+ const inputVariants = tv({
4
+ extend: inputBaseVariant,
5
+ slots: {
6
+ adornmentStart:
7
+ "pointer-events-none shrink-0 body-small text-neutral-900 dark:text-neutral-200",
8
+ adornmentEnd: "shrink-0 body-small text-neutral-900 dark:text-neutral-200",
9
+ base: "flex h-10 items-center gap-2 pr-1",
10
+ input:
11
+ "h-full w-full appearance-none border-0 bg-transparent p-0 [font-size:inherit] leading-[inherit] focus:shadow-none focus:ring-0 focus:outline-0",
12
+ },
13
+ variants: {
14
+ disabled: {
15
+ true: { input: "cursor-not-allowed" },
16
+ },
17
+ },
18
+ });
19
+
20
+ export { inputVariants };
@@ -1,3 +1,33 @@
1
+ <script module>
2
+ /** @type {Map<string, Set>} valueCheckers */
3
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity
4
+ const valueCheckers = new Map();
5
+
6
+ const checkValues = (name) => {
7
+ const checkers = valueCheckers.get(name);
8
+ for (const fn of checkers?.values() ?? []) {
9
+ fn?.();
10
+ }
11
+ };
12
+
13
+ const addValueUpdater = (name, checker) => {
14
+ let checkerSet = valueCheckers.get(name);
15
+ if (!checkerSet) {
16
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity
17
+ checkerSet = new Set();
18
+ valueCheckers.set(name, checkerSet);
19
+ }
20
+ checkerSet.add(checker);
21
+
22
+ return () => {
23
+ checkerSet.delete(checker);
24
+ if (!checkerSet.size) {
25
+ valueCheckers.delete(name);
26
+ }
27
+ };
28
+ };
29
+ </script>
30
+
1
31
  <script>
2
32
  import { getContext } from "svelte";
3
33
  import { radioVariants } from "./radio.variants.js";
@@ -27,6 +57,7 @@
27
57
  ...rest
28
58
  } = $props();
29
59
 
60
+ let element = $state();
30
61
  let store = getContext("form-field-store") ?? null;
31
62
 
32
63
  let localValues = $derived.by(() => {
@@ -39,10 +70,31 @@
39
70
  required: required ?? storeValues.required ?? false,
40
71
  };
41
72
  });
73
+
74
+ const handleChange = (e) => {
75
+ if (name?.length) {
76
+ checkValues(name);
77
+ } else {
78
+ checked = e.target.checked;
79
+ }
80
+ };
81
+
82
+ $effect(() => {
83
+ let offUpdater;
84
+ if (name) {
85
+ offUpdater = addValueUpdater(name, () => {
86
+ checked = element?.checked || false;
87
+ });
88
+ }
89
+
90
+ return () => {
91
+ offUpdater?.();
92
+ };
93
+ });
42
94
  </script>
43
95
 
44
96
  <input
45
- onchange={(e) => (checked = !checked ? e.target.checked : checked)}
97
+ bind:this={element}
46
98
  {checked}
47
99
  class={radioVariants({
48
100
  checked,
@@ -53,7 +105,8 @@
53
105
  disabled={localValues.disabled}
54
106
  id={localValues.id}
55
107
  {name}
108
+ onchange={handleChange}
56
109
  required={localValues.required}
57
- type="checkbox"
110
+ type="radio"
58
111
  {value}
59
112
  {...rest} />
@@ -6,8 +6,8 @@
6
6
  * @typedef {Object} Props
7
7
  * @property {import('svelte').Snippet} [children] Content inside the tag – can be text, HTML, or Svelte components
8
8
  * @property {string} [class=""] Additional CSS classes for the tag
9
- * @property {string} [icon=""] Name of the icon to display
10
- * @property {"start" | "end"} [iconPosition="start"] Position of the icon relative to the content
9
+ * @property {string} [iconEnd=""] Name of the icon to display at the end
10
+ * @property {string} [iconStart=""] Name of the icon to display at the start
11
11
  * @property {boolean} [selected=false] Whether the tag is in a visually selected state
12
12
  * @property {"round" | "round-big"} [shape="round"] Shape of the tag
13
13
  * @property {"small" | "big"} [size="small"] Size of the tag
@@ -18,8 +18,8 @@
18
18
  let {
19
19
  children,
20
20
  class: className,
21
- icon = "",
22
- iconPosition = "start",
21
+ iconEnd = "",
22
+ iconStart = "",
23
23
  selected = false,
24
24
  shape = "round",
25
25
  size = "small",
@@ -31,7 +31,6 @@
31
31
  <button
32
32
  class={tagVariants({
33
33
  class: className,
34
- iconPosition,
35
34
  selected,
36
35
  shape,
37
36
  size,
@@ -39,10 +38,13 @@
39
38
  })}
40
39
  type="button"
41
40
  {...rest}>
42
- {#if icon}
43
- <Icon name={icon} size={14} />
41
+ {#if iconStart}
42
+ <Icon name={iconStart} size={14} />
44
43
  {/if}
45
44
  <span>
46
45
  {@render children?.()}
47
46
  </span>
47
+ {#if iconEnd}
48
+ <Icon name={iconEnd} size={14} />
49
+ {/if}
48
50
  </button>
@@ -13,13 +13,13 @@ declare const Tag: import("svelte").Component<{
13
13
  */
14
14
  class?: string;
15
15
  /**
16
- * Name of the icon to display
16
+ * Name of the icon to display at the end
17
17
  */
18
- icon?: string;
18
+ iconEnd?: string;
19
19
  /**
20
- * Position of the icon relative to the content
20
+ * Name of the icon to display at the start
21
21
  */
22
- iconPosition?: "start" | "end";
22
+ iconStart?: string;
23
23
  /**
24
24
  * Whether the tag is in a visually selected state
25
25
  */
@@ -47,13 +47,13 @@ type Props = {
47
47
  */
48
48
  class?: string;
49
49
  /**
50
- * Name of the icon to display
50
+ * Name of the icon to display at the end
51
51
  */
52
- icon?: string;
52
+ iconEnd?: string;
53
53
  /**
54
- * Position of the icon relative to the content
54
+ * Name of the icon to display at the start
55
55
  */
56
- iconPosition?: "start" | "end";
56
+ iconStart?: string;
57
57
  /**
58
58
  * Whether the tag is in a visually selected state
59
59
  */
@@ -1,7 +1,4 @@
1
1
  export const tagVariants: import("tailwind-variants").TVReturnType<{
2
- iconPosition: {
3
- end: string;
4
- };
5
2
  selected: {
6
3
  true: string;
7
4
  };
@@ -18,9 +15,6 @@ export const tagVariants: import("tailwind-variants").TVReturnType<{
18
15
  outline: string;
19
16
  };
20
17
  }, undefined, string[], {
21
- iconPosition: {
22
- end: string;
23
- };
24
18
  selected: {
25
19
  true: string;
26
20
  };
@@ -37,9 +31,6 @@ export const tagVariants: import("tailwind-variants").TVReturnType<{
37
31
  outline: string;
38
32
  };
39
33
  }, undefined, import("tailwind-variants").TVReturnType<{
40
- iconPosition: {
41
- end: string;
42
- };
43
34
  selected: {
44
35
  true: string;
45
36
  };
@@ -8,11 +8,8 @@ const tagVariants = tv({
8
8
  "border border-neutral-100 hover:border-neutral-200 dark:border-neutral-700 hover:dark:border-neutral-700",
9
9
  ],
10
10
  variants: {
11
- iconPosition: {
12
- end: "flex-row-reverse",
13
- },
14
11
  selected: {
15
- true: "border-neutral-900 !bg-neutral-900 text-neutral-100 dark:border-blue-400 dark:!bg-blue-400",
12
+ true: "border-neutral-900 bg-neutral-900! text-neutral-100 dark:border-blue-400 dark:bg-blue-400!",
16
13
  },
17
14
  shape: {
18
15
  round: "rounded-sm",
@@ -0,0 +1,95 @@
1
+ <script>
2
+ import { Calendar } from "bits-ui";
3
+ import { Icon } from "../../../index.js";
4
+ import { calendarVariants } from "./calendar.variant.js";
5
+ import RootContext from "./RootContext.svelte";
6
+
7
+ /**
8
+ * @typedef {import("bits-ui").CalendarRootPropsWithoutHTML} CalendarRootProps
9
+ *
10
+ * @typedef {Object} Props
11
+ * @property {import('svelte').Snippet} [children] Children content – can be text, HTML, or other Svelte components
12
+ * @property {string} [class=""] Additional CSS classes to apply to the component
13
+ * @property {boolean} [hideHeader=false] Whether to show the header or not
14
+ * @property {number} [maxMonths=false] The maximum of months to display side by side
15
+ */
16
+
17
+ /** @type {Omit<CalendarRootProps, "disabled" | "disableDaysOutsideMonth" | "isDateDisabled" | "numberOfMonths" | "pagedNavigation" | "weekStartsOn"> & Props} */
18
+ let {
19
+ children: _children,
20
+ class: className = "",
21
+ hideHeader = false,
22
+ locale = "de",
23
+ maxDays = 2,
24
+ maxMonths = 1,
25
+ ref = $bindable(null),
26
+ type,
27
+ value = $bindable(),
28
+ weekdayFormat = "short",
29
+ ...rest
30
+ } = $props();
31
+
32
+ let ro;
33
+ let numberOfMonths = $state(1);
34
+ let styles = $derived(calendarVariants());
35
+
36
+ const setValue = (newValue) => {
37
+ if (Array.isArray(newValue)) {
38
+ // make sure dates are sorted for the range selection
39
+ value = newValue.toSorted();
40
+ } else {
41
+ value = newValue;
42
+ }
43
+ };
44
+
45
+ const updateVisibleMonths = (table, parentElement) => {
46
+ numberOfMonths = Math.min(
47
+ Math.max(Math.floor(parentElement.offsetWidth / table.offsetWidth), 1),
48
+ maxMonths,
49
+ );
50
+ };
51
+
52
+ $effect(() => {
53
+ if (maxMonths > 1 && ref?.parentElement) {
54
+ const firstTable = ref.querySelector("[data-calendar-grid]");
55
+ ro = new ResizeObserver(() => {
56
+ updateVisibleMonths(firstTable, ref.parentElement);
57
+ });
58
+ ro.observe(ref.parentElement);
59
+ }
60
+
61
+ return () => {
62
+ numberOfMonths = 1;
63
+ ro?.disconnect();
64
+ };
65
+ });
66
+ </script>
67
+
68
+ <Calendar.Root
69
+ class={styles.base({ class: className })}
70
+ {locale}
71
+ {maxDays}
72
+ {numberOfMonths}
73
+ pagedNavigation
74
+ bind:ref
75
+ {type}
76
+ bind:value={() => value, setValue}
77
+ {weekdayFormat}
78
+ {...rest}>
79
+ {#snippet children({ months, weekdays })}
80
+ {#if !hideHeader}
81
+ <Calendar.Header class={styles.header({ class: className })} {...rest}>
82
+ <Calendar.PrevButton class={styles.headerBtn({ class: "rotate-90" })}>
83
+ <Icon name="chevronDown" size={20} />
84
+ </Calendar.PrevButton>
85
+ <Calendar.Heading class={styles.heading()} />
86
+ <Calendar.NextButton class={styles.headerBtn({ class: "rotate-270" })}>
87
+ <Icon name="chevronDown" size={20} />
88
+ </Calendar.NextButton>
89
+ </Calendar.Header>
90
+ {/if}
91
+ <RootContext {maxDays} {months} {value} {weekdays}>
92
+ {@render _children?.()}
93
+ </RootContext>
94
+ {/snippet}
95
+ </Calendar.Root>