@ims360/svelte-ivory 0.3.0 → 0.3.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 (37) hide show
  1. package/dist/components/basic/Element.svelte +81 -0
  2. package/dist/components/basic/Element.svelte.d.ts +30 -0
  3. package/dist/components/basic/Element.svelte.d.ts.map +1 -0
  4. package/dist/components/basic/MarkedText.svelte +70 -0
  5. package/dist/components/basic/MarkedText.svelte.d.ts +17 -0
  6. package/dist/components/basic/MarkedText.svelte.d.ts.map +1 -0
  7. package/dist/components/basic/Textarea.svelte +46 -0
  8. package/dist/components/basic/Textarea.svelte.d.ts +15 -0
  9. package/dist/components/basic/Textarea.svelte.d.ts.map +1 -0
  10. package/dist/components/basic/checkbox/Checkbox.svelte +2 -2
  11. package/dist/components/basic/checkbox/Checkbox.svelte.d.ts +2 -2
  12. package/dist/components/basic/checkbox/Checkbox.svelte.d.ts.map +1 -1
  13. package/dist/components/basic/index.d.ts +5 -4
  14. package/dist/components/basic/index.d.ts.map +1 -1
  15. package/dist/components/basic/index.js +3 -2
  16. package/dist/components/basic/toggle/Toggle.svelte +2 -2
  17. package/dist/components/basic/toggle/Toggle.svelte.d.ts +2 -2
  18. package/dist/components/basic/toggle/Toggle.svelte.d.ts.map +1 -1
  19. package/dist/components/inputs/TextareaInput.svelte +23 -0
  20. package/dist/components/inputs/TextareaInput.svelte.d.ts +7 -0
  21. package/dist/components/inputs/TextareaInput.svelte.d.ts.map +1 -0
  22. package/dist/components/inputs/index.d.ts +1 -0
  23. package/dist/components/inputs/index.d.ts.map +1 -1
  24. package/dist/components/inputs/index.js +1 -0
  25. package/dist/components/table/Column.svelte +19 -19
  26. package/dist/components/table/Column.svelte.d.ts +1 -0
  27. package/dist/components/table/Column.svelte.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/lib/components/basic/Element.svelte +81 -0
  30. package/src/lib/components/basic/MarkedText.svelte +70 -0
  31. package/src/lib/components/basic/Textarea.svelte +46 -0
  32. package/src/lib/components/basic/checkbox/Checkbox.svelte +2 -2
  33. package/src/lib/components/basic/index.ts +10 -4
  34. package/src/lib/components/basic/toggle/Toggle.svelte +2 -2
  35. package/src/lib/components/inputs/TextareaInput.svelte +23 -0
  36. package/src/lib/components/inputs/index.ts +1 -0
  37. package/src/lib/components/table/Column.svelte +19 -19
@@ -0,0 +1,81 @@
1
+ <script lang="ts" module>
2
+ import { merge } from '../../utils/functions';
3
+ import type {
4
+ HTMLAttributeAnchorTarget,
5
+ HTMLAttributes,
6
+ MouseEventHandler
7
+ } from 'svelte/elements';
8
+ import type { TransitionConfig } from 'svelte/transition';
9
+
10
+ export type AnchorAttributes = {
11
+ download?: string | undefined | null;
12
+ href?: string | undefined | null;
13
+ hreflang?: string | undefined | null;
14
+ rel?: string | undefined | null;
15
+ target?: HTMLAttributeAnchorTarget | undefined | null;
16
+ type?: string | undefined | null;
17
+ referrerpolicy?: ReferrerPolicy | undefined | null;
18
+ };
19
+
20
+ export type ButtonAttributes = {
21
+ onclick: MouseEventHandler<HTMLElement>;
22
+ disabled?: boolean | undefined | null;
23
+ form?: string | undefined | null;
24
+ name?: string | undefined | null;
25
+ type?: 'submit' | 'reset' | 'button' | undefined | null;
26
+ value?: string | string[] | number | undefined | null;
27
+ };
28
+
29
+ export type ElementProps = HTMLAttributes<HTMLElement> & {
30
+ inTransition?: (element: HTMLElement) => TransitionConfig;
31
+ outTransition?: (element: HTMLElement) => TransitionConfig;
32
+ } & (AnchorAttributes | ButtonAttributes | HTMLAttributes<HTMLDivElement>);
33
+ </script>
34
+
35
+ <script lang="ts">
36
+ const noop = () => ({});
37
+ let {
38
+ div = $bindable(),
39
+ inTransition = noop,
40
+ outTransition = noop,
41
+ ...props
42
+ }: ElementProps & { div?: HTMLElement } = $props();
43
+
44
+ function isAnchor(props: ElementProps): props is AnchorAttributes {
45
+ return 'href' in props && typeof props.href !== 'undefined';
46
+ }
47
+
48
+ function isButton(props: ElementProps): props is ButtonAttributes {
49
+ return ('onclick' in props && typeof props.onclick !== 'undefined') || 'type' in props;
50
+ }
51
+ </script>
52
+
53
+ {#if 'disabled' in props && props.disabled}
54
+ <div
55
+ {...props}
56
+ in:inTransition
57
+ out:outTransition
58
+ class={merge(props.class, 'pointer-events-none opacity-60 grayscale')}
59
+ bind:this={div}
60
+ >
61
+ {@render props.children?.()}
62
+ </div>
63
+ {:else if isAnchor(props)}
64
+ <a {...props} in:inTransition out:outTransition bind:this={div}>
65
+ {@render props.children?.()}
66
+ </a>
67
+ {:else if isButton(props)}
68
+ <button
69
+ {...props}
70
+ in:inTransition
71
+ out:outTransition
72
+ type={props.type || 'button'}
73
+ bind:this={div}
74
+ >
75
+ {@render props.children?.()}
76
+ </button>
77
+ {:else}
78
+ <div {...props} in:inTransition out:outTransition bind:this={div}>
79
+ {@render props.children?.()}
80
+ </div>
81
+ {/if}
@@ -0,0 +1,30 @@
1
+ import type { HTMLAttributeAnchorTarget, HTMLAttributes, MouseEventHandler } from 'svelte/elements';
2
+ import type { TransitionConfig } from 'svelte/transition';
3
+ export type AnchorAttributes = {
4
+ download?: string | undefined | null;
5
+ href?: string | undefined | null;
6
+ hreflang?: string | undefined | null;
7
+ rel?: string | undefined | null;
8
+ target?: HTMLAttributeAnchorTarget | undefined | null;
9
+ type?: string | undefined | null;
10
+ referrerpolicy?: ReferrerPolicy | undefined | null;
11
+ };
12
+ export type ButtonAttributes = {
13
+ onclick: MouseEventHandler<HTMLElement>;
14
+ disabled?: boolean | undefined | null;
15
+ form?: string | undefined | null;
16
+ name?: string | undefined | null;
17
+ type?: 'submit' | 'reset' | 'button' | undefined | null;
18
+ value?: string | string[] | number | undefined | null;
19
+ };
20
+ export type ElementProps = HTMLAttributes<HTMLElement> & {
21
+ inTransition?: (element: HTMLElement) => TransitionConfig;
22
+ outTransition?: (element: HTMLElement) => TransitionConfig;
23
+ } & (AnchorAttributes | ButtonAttributes | HTMLAttributes<HTMLDivElement>);
24
+ type $$ComponentProps = ElementProps & {
25
+ div?: HTMLElement;
26
+ };
27
+ declare const Element: import("svelte").Component<$$ComponentProps, {}, "div">;
28
+ type Element = ReturnType<typeof Element>;
29
+ export default Element;
30
+ //# sourceMappingURL=Element.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Element.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/basic/Element.svelte.ts"],"names":[],"mappings":"AAII,OAAO,KAAK,EACR,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,yBAAyB,GAAG,SAAS,GAAG,IAAI,CAAC;IACtD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACjC,cAAc,CAAC,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,CAAC;CACtD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC3B,OAAO,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,cAAc,CAAC,WAAW,CAAC,GAAG;IACrD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,gBAAgB,CAAC;IAC1D,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,gBAAgB,CAAC;CAC9D,GAAG,CAAC,gBAAgB,GAAG,gBAAgB,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC;AAE9E,KAAK,gBAAgB,GAAI,YAAY,GAAG;IAAE,GAAG,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAyC/D,QAAA,MAAM,OAAO,yDAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
@@ -0,0 +1,70 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassValue } from 'svelte/elements';
4
+
5
+ export type MarkedTextProps = {
6
+ class?: ClassValue;
7
+ content: string | undefined;
8
+ search: string | undefined;
9
+ element?: 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
10
+ id?: string | undefined;
11
+ children?: Snippet<[{ match: string }]>;
12
+ };
13
+ </script>
14
+
15
+ <script lang="ts">
16
+ let {
17
+ class: clazz = 'shrink-0 whitespace-nowrap text-ellipsis overflow-hidden max-w-full',
18
+ content,
19
+ search,
20
+ element = 'p',
21
+ id,
22
+ children
23
+ }: MarkedTextProps = $props();
24
+
25
+ /**
26
+ * @param str
27
+ * @param search
28
+ * @return tokens: list with {match, prev}, where 'match' matches the search (case-insensitive) and prev is the string between 'match' and the prev 'match' (or start)
29
+ * @return tail: the string after the last match
30
+ */
31
+ const split = (str: string, search: string) => {
32
+ const matchLen = search.length;
33
+ var tokens: { match: string; prev: string }[] = [];
34
+ let pos = str.toLowerCase().search(search.toLowerCase());
35
+ while (pos != -1) {
36
+ tokens.push({
37
+ match: str.slice(pos, pos + matchLen),
38
+ prev: str.slice(0, pos)
39
+ });
40
+ str = str.slice(pos + matchLen);
41
+ pos = str.search(search);
42
+ }
43
+ return {
44
+ tokens,
45
+ tail: str
46
+ };
47
+ };
48
+
49
+ const { tokens, tail } = $derived.by(() => {
50
+ if (!search || !content) return { tokens: [], tail: content };
51
+ return split(content, search);
52
+ });
53
+ </script>
54
+
55
+ <!-- @component
56
+ marks text-parts matching the given search parameter
57
+ -->
58
+ <svelte:element this={element} class={[clazz]} {id}>
59
+ {#each tokens as token (token)}
60
+ {token.prev}
61
+ {#if children}
62
+ {@render children?.({ match: token.match })}
63
+ {:else}
64
+ <mark class="bg-primary-500 text-surface-50 shrink-0 rounded-sm px-px py-0.5">
65
+ {token.match}
66
+ </mark>
67
+ {/if}
68
+ {/each}
69
+ {tail}
70
+ </svelte:element>
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ export type MarkedTextProps = {
4
+ class?: ClassValue;
5
+ content: string | undefined;
6
+ search: string | undefined;
7
+ element?: 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
8
+ id?: string | undefined;
9
+ children?: Snippet<[{
10
+ match: string;
11
+ }]>;
12
+ };
13
+ /** marks text-parts matching the given search parameter */
14
+ declare const MarkedText: import("svelte").Component<MarkedTextProps, {}, "">;
15
+ type MarkedText = ReturnType<typeof MarkedText>;
16
+ export default MarkedText;
17
+ //# sourceMappingURL=MarkedText.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkedText.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/basic/MarkedText.svelte.ts"],"names":[],"mappings":"AAGI,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,eAAe,GAAG;IAC1B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC3C,CAAC;AA6DN,2DAA2D;AAC3D,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ import { merge } from '../../utils/functions';
3
+ import type { ClassValue, HTMLAttributes } from 'svelte/elements';
4
+
5
+ interface Props extends HTMLAttributes<HTMLTextAreaElement> {
6
+ class?: ClassValue;
7
+ value?: string;
8
+ disabled?: boolean;
9
+ placeholder?: string;
10
+ name?: string;
11
+ }
12
+
13
+ let { class: clazz, value = $bindable(), ...rest }: Props = $props();
14
+
15
+ let textareaEl = $state<HTMLTextAreaElement>();
16
+
17
+ function autoResize() {
18
+ if (!textareaEl) return;
19
+ textareaEl.style.height = 'auto';
20
+ textareaEl.style.height = `${textareaEl.scrollHeight}px`;
21
+ }
22
+
23
+ $effect(() => {
24
+ value;
25
+ autoResize();
26
+ });
27
+
28
+ export function focus() {
29
+ textareaEl?.focus();
30
+ }
31
+
32
+ export function isActive() {
33
+ return document.activeElement === textareaEl;
34
+ }
35
+ </script>
36
+
37
+ <textarea
38
+ class={merge(
39
+ 'max-h-96 w-full resize-none overflow-y-auto border-none bg-transparent ring-0 outline-0 transition-all',
40
+ clazz
41
+ )}
42
+ bind:this={textareaEl}
43
+ bind:value
44
+ rows="1"
45
+ {...rest}
46
+ ></textarea>
@@ -0,0 +1,15 @@
1
+ import type { ClassValue, HTMLAttributes } from 'svelte/elements';
2
+ interface Props extends HTMLAttributes<HTMLTextAreaElement> {
3
+ class?: ClassValue;
4
+ value?: string;
5
+ disabled?: boolean;
6
+ placeholder?: string;
7
+ name?: string;
8
+ }
9
+ declare const Textarea: import("svelte").Component<Props, {
10
+ focus: () => void;
11
+ isActive: () => boolean;
12
+ }, "value">;
13
+ type Textarea = ReturnType<typeof Textarea>;
14
+ export default Textarea;
15
+ //# sourceMappingURL=Textarea.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Textarea.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/basic/Textarea.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG9D,UAAU,KAAM,SAAQ,cAAc,CAAC,mBAAmB,CAAC;IACvD,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAqCL,QAAA,MAAM,QAAQ;;;WAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -7,7 +7,7 @@
7
7
  import type { ClassValue } from 'svelte/elements';
8
8
  import { scale } from 'svelte/transition';
9
9
 
10
- export interface CheckboxProps extends IvoryComponent<HTMLElement> {
10
+ export type CheckboxProps = IvoryComponent<HTMLElement> & {
11
11
  class?: ClassValue;
12
12
  /** `checked` has prioriy over `partial` */
13
13
  checked?: boolean | null;
@@ -17,7 +17,7 @@
17
17
  /** if true, the onclick handler will not be called */
18
18
  disabled?: boolean;
19
19
  onclick?: () => void;
20
- }
20
+ };
21
21
  </script>
22
22
 
23
23
  <!--
@@ -1,6 +1,6 @@
1
1
  import type { IvoryComponent } from '../../../types';
2
2
  import type { ClassValue } from 'svelte/elements';
3
- export interface CheckboxProps extends IvoryComponent<HTMLElement> {
3
+ export type CheckboxProps = IvoryComponent<HTMLElement> & {
4
4
  class?: ClassValue;
5
5
  /** `checked` has prioriy over `partial` */
6
6
  checked?: boolean | null;
@@ -10,7 +10,7 @@ export interface CheckboxProps extends IvoryComponent<HTMLElement> {
10
10
  /** if true, the onclick handler will not be called */
11
11
  disabled?: boolean;
12
12
  onclick?: () => void;
13
- }
13
+ };
14
14
  /** It's a checkbox */
15
15
  declare const Checkbox: import("svelte").Component<CheckboxProps, {}, "">;
16
16
  type Checkbox = ReturnType<typeof Checkbox>;
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/basic/checkbox/Checkbox.svelte.ts"],"names":[],"mappings":"AAII,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,MAAM,WAAW,aAAc,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC9D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAuDL,sBAAsB;AACtB,QAAA,MAAM,QAAQ,mDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Checkbox.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/basic/checkbox/Checkbox.svelte.ts"],"names":[],"mappings":"AAII,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,CAAC,GAAG;IACtD,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAuDN,sBAAsB;AACtB,QAAA,MAAM,QAAQ,mDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -1,5 +1,6 @@
1
- export * from './checkbox/Checkbox.svelte';
2
- export { default as Checkbox } from './checkbox/Checkbox.svelte';
3
- export * from './toggle/Toggle.svelte';
4
- export { default as Toggle } from './toggle/Toggle.svelte';
1
+ export { default as Checkbox, type CheckboxProps } from './checkbox/Checkbox.svelte';
2
+ export { default as Element, type AnchorAttributes, type ButtonAttributes, type ElementProps } from './Element.svelte';
3
+ export { default as MarkedText, type MarkedTextProps } from './MarkedText.svelte';
4
+ export { default as Textarea } from './Textarea.svelte';
5
+ export { default as Toggle, type ToggleProps } from './toggle/Toggle.svelte';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/basic/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACjE,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/basic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACrF,OAAO,EACH,OAAO,IAAI,OAAO,EAClB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
@@ -1,4 +1,5 @@
1
- export * from './checkbox/Checkbox.svelte';
2
1
  export { default as Checkbox } from './checkbox/Checkbox.svelte';
3
- export * from './toggle/Toggle.svelte';
2
+ export { default as Element } from './Element.svelte';
3
+ export { default as MarkedText } from './MarkedText.svelte';
4
+ export { default as Textarea } from './Textarea.svelte';
4
5
  export { default as Toggle } from './toggle/Toggle.svelte';
@@ -4,11 +4,11 @@
4
4
  import type { Snippet } from 'svelte';
5
5
  import type { ClassValue } from 'svelte/elements';
6
6
 
7
- export interface ToggleProps extends IvoryComponent<HTMLElement> {
7
+ export type ToggleProps = IvoryComponent<HTMLElement> & {
8
8
  value?: boolean;
9
9
  class?: ClassValue;
10
10
  children?: Snippet;
11
- }
11
+ };
12
12
  </script>
13
13
 
14
14
  <script lang="ts">
@@ -1,11 +1,11 @@
1
1
  import type { IvoryComponent } from '../../../types';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { ClassValue } from 'svelte/elements';
4
- export interface ToggleProps extends IvoryComponent<HTMLElement> {
4
+ export type ToggleProps = IvoryComponent<HTMLElement> & {
5
5
  value?: boolean;
6
6
  class?: ClassValue;
7
7
  children?: Snippet;
8
- }
8
+ };
9
9
  declare const Toggle: import("svelte").Component<ToggleProps, {}, "">;
10
10
  type Toggle = ReturnType<typeof Toggle>;
11
11
  export default Toggle;
@@ -1 +1 @@
1
- {"version":3,"file":"Toggle.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/basic/toggle/Toggle.svelte.ts"],"names":[],"mappings":"AAGI,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,WAAW,CAAC;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AA8BL,QAAA,MAAM,MAAM,iDAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Toggle.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/basic/toggle/Toggle.svelte.ts"],"names":[],"mappings":"AAGI,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,GAAG;IACpD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AA8BN,QAAA,MAAM,MAAM,iDAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import TextArea from '../basic/Textarea.svelte';
3
+ import Input, { type InputProps } from './Input.svelte';
4
+
5
+ let { ...props }: InputProps<string> = $props();
6
+
7
+ let inputElement = $state<TextArea>();
8
+ export function focus() {
9
+ inputElement?.focus();
10
+ }
11
+ </script>
12
+
13
+ <Input {...props}>
14
+ {#snippet children(inputProps)}
15
+ {@const { name } = props.form.as?.('text')}
16
+ <TextArea
17
+ {...inputProps}
18
+ {name}
19
+ bind:value={props.form.value, props.form.set}
20
+ bind:this={inputElement}
21
+ />
22
+ {/snippet}
23
+ </Input>
@@ -0,0 +1,7 @@
1
+ import { type InputProps } from './Input.svelte';
2
+ declare const TextareaInput: import("svelte").Component<InputProps<string>, {
3
+ focus: () => void;
4
+ }, "">;
5
+ type TextareaInput = ReturnType<typeof TextareaInput>;
6
+ export default TextareaInput;
7
+ //# sourceMappingURL=TextareaInput.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextareaInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/inputs/TextareaInput.svelte.ts"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAuBxD,QAAA,MAAM,aAAa;;MAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -10,6 +10,7 @@ export { default as PasswordCreateInput, type PasswordCreateInputProps, type Pas
10
10
  export { default as PasswordInput } from './PasswordInput.svelte';
11
11
  export { default as Select } from './select/Select.svelte';
12
12
  export { default as SelectOption } from './select/SelectOption.svelte';
13
+ export { default as TextareaInput } from './TextareaInput.svelte';
13
14
  export { default as TextInput } from './TextInput.svelte';
14
15
  export { default as ToggleInput } from './ToggleInput.svelte';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/inputs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EACH,OAAO,IAAI,kBAAkB,EAC7B,KAAK,uBAAuB,EAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACH,OAAO,IAAI,mBAAmB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/inputs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EACH,OAAO,IAAI,kBAAkB,EAC7B,KAAK,uBAAuB,EAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACH,OAAO,IAAI,mBAAmB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAC3B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
@@ -10,5 +10,6 @@ export { default as PasswordCreateInput } from './PasswordCreateInput.svelte';
10
10
  export { default as PasswordInput } from './PasswordInput.svelte';
11
11
  export { default as Select } from './select/Select.svelte';
12
12
  export { default as SelectOption } from './select/SelectOption.svelte';
13
+ export { default as TextareaInput } from './TextareaInput.svelte';
13
14
  export { default as TextInput } from './TextInput.svelte';
14
15
  export { default as ToggleInput } from './ToggleInput.svelte';
@@ -3,6 +3,7 @@
3
3
  import { merge } from '../../utils/functions';
4
4
  import { type Snippet } from 'svelte';
5
5
  import type { ClassValue } from 'svelte/elements';
6
+ import Element from '../basic/Element.svelte';
6
7
  import type { ColumnConfig } from './columnController.svelte';
7
8
  import { getRowContext } from './Row.svelte';
8
9
  import { getTableContext } from './Table.svelte';
@@ -12,6 +13,7 @@
12
13
  /** If the type is incorrect pass the "row" property with the right type */
13
14
  children: Snippet;
14
15
  onclick?: (e: Event) => void | Promise<void>;
16
+ href?: string;
15
17
  /** Cannot be used with resizable columns*/
16
18
  ignoreWidth?: boolean;
17
19
  offsetNestingLevel?: number;
@@ -21,37 +23,38 @@
21
23
  <script lang="ts">
22
24
  let {
23
25
  class: clazz,
24
- children,
25
26
  onclick,
27
+ href,
26
28
  ignoreWidth = false,
29
+ offsetNestingLevel = 0,
27
30
  // ColumnConfig
31
+ id,
32
+ width,
33
+ minWidth,
28
34
  resizable = true,
29
- offsetNestingLevel = 0,
35
+ header,
30
36
  ...props
31
37
  }: ColumnProps = $props();
32
38
 
33
39
  // Register the new column if this is the first table row that was rendered
34
40
  const tableContext = getTableContext();
35
- const column = tableContext.registerColumn({ resizable, ...props });
41
+ const column = tableContext.registerColumn({ id, width, minWidth, resizable, header });
36
42
  const rowContext = getRowContext();
37
43
 
38
44
  const finalOnClick = $derived(onclick || rowContext.onclick);
39
- const allowClicking = $derived(!!(onclick || rowContext.onclick));
40
-
41
- const element = $derived.by(() => {
42
- if (finalOnClick) return 'button';
43
- if (rowContext.href) return 'a';
44
- return 'div';
45
+ const finalHref = $derived.by(() => {
46
+ if (finalOnClick) return undefined;
47
+ return href || rowContext.href;
45
48
  });
46
49
 
47
50
  // passes updated props to the column
48
51
  $effect(() => {
49
- column.updateConfig({ resizable, ...props });
52
+ column.updateConfig({ resizable, minWidth, id, header });
50
53
  });
51
54
 
52
55
  // this must be separate to the above effect, since otherwise the width would be reset on every scroll
53
56
  $effect(() => {
54
- if (!resizable && typeof props.width !== 'undefined') column.width = props.width;
57
+ if (!resizable && typeof width !== 'undefined') column.width = width;
55
58
  });
56
59
 
57
60
  const widthStyle = $derived(
@@ -60,11 +63,10 @@
60
63
  </script>
61
64
 
62
65
  <!-- svelte-ignore a11y_no_static_element_interactions -->
63
- <svelte:element
64
- this={element}
65
- onclick={allowClicking ? finalOnClick : undefined}
66
- href={!allowClicking ? rowContext.href : undefined}
67
- type={allowClicking ? 'button' : undefined}
66
+ <Element
67
+ {...props}
68
+ onclick={finalOnClick}
69
+ href={finalHref}
68
70
  style={ignoreWidth ? '' : `width: ${widthStyle}`}
69
71
  class={merge([
70
72
  'box-border flex h-full shrink-0 flex-row items-center justify-start gap-1 truncate',
@@ -72,6 +74,4 @@
72
74
  theme.current.table?.column?.class,
73
75
  clazz
74
76
  ])}
75
- >
76
- {@render children()}
77
- </svelte:element>
77
+ />
@@ -6,6 +6,7 @@ export interface ColumnProps extends ColumnConfig {
6
6
  /** If the type is incorrect pass the "row" property with the right type */
7
7
  children: Snippet;
8
8
  onclick?: (e: Event) => void | Promise<void>;
9
+ href?: string;
9
10
  /** Cannot be used with resizable columns*/
10
11
  ignoreWidth?: boolean;
11
12
  offsetNestingLevel?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"Column.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/table/Column.svelte.ts"],"names":[],"mappings":"AAKI,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI9D,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC7C,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,2CAA2C;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAyDL,QAAA,MAAM,MAAM,iDAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Column.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/table/Column.svelte.ts"],"names":[],"mappings":"AAKI,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI9D,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC7C,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAwDL,QAAA,MAAM,MAAM,iDAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ims360/svelte-ivory",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "keywords": [
5
5
  "svelte"
6
6
  ],
@@ -0,0 +1,81 @@
1
+ <script lang="ts" module>
2
+ import { merge } from '$lib/utils/functions';
3
+ import type {
4
+ HTMLAttributeAnchorTarget,
5
+ HTMLAttributes,
6
+ MouseEventHandler
7
+ } from 'svelte/elements';
8
+ import type { TransitionConfig } from 'svelte/transition';
9
+
10
+ export type AnchorAttributes = {
11
+ download?: string | undefined | null;
12
+ href?: string | undefined | null;
13
+ hreflang?: string | undefined | null;
14
+ rel?: string | undefined | null;
15
+ target?: HTMLAttributeAnchorTarget | undefined | null;
16
+ type?: string | undefined | null;
17
+ referrerpolicy?: ReferrerPolicy | undefined | null;
18
+ };
19
+
20
+ export type ButtonAttributes = {
21
+ onclick: MouseEventHandler<HTMLElement>;
22
+ disabled?: boolean | undefined | null;
23
+ form?: string | undefined | null;
24
+ name?: string | undefined | null;
25
+ type?: 'submit' | 'reset' | 'button' | undefined | null;
26
+ value?: string | string[] | number | undefined | null;
27
+ };
28
+
29
+ export type ElementProps = HTMLAttributes<HTMLElement> & {
30
+ inTransition?: (element: HTMLElement) => TransitionConfig;
31
+ outTransition?: (element: HTMLElement) => TransitionConfig;
32
+ } & (AnchorAttributes | ButtonAttributes | HTMLAttributes<HTMLDivElement>);
33
+ </script>
34
+
35
+ <script lang="ts">
36
+ const noop = () => ({});
37
+ let {
38
+ div = $bindable(),
39
+ inTransition = noop,
40
+ outTransition = noop,
41
+ ...props
42
+ }: ElementProps & { div?: HTMLElement } = $props();
43
+
44
+ function isAnchor(props: ElementProps): props is AnchorAttributes {
45
+ return 'href' in props && typeof props.href !== 'undefined';
46
+ }
47
+
48
+ function isButton(props: ElementProps): props is ButtonAttributes {
49
+ return ('onclick' in props && typeof props.onclick !== 'undefined') || 'type' in props;
50
+ }
51
+ </script>
52
+
53
+ {#if 'disabled' in props && props.disabled}
54
+ <div
55
+ {...props}
56
+ in:inTransition
57
+ out:outTransition
58
+ class={merge(props.class, 'pointer-events-none opacity-60 grayscale')}
59
+ bind:this={div}
60
+ >
61
+ {@render props.children?.()}
62
+ </div>
63
+ {:else if isAnchor(props)}
64
+ <a {...props} in:inTransition out:outTransition bind:this={div}>
65
+ {@render props.children?.()}
66
+ </a>
67
+ {:else if isButton(props)}
68
+ <button
69
+ {...props}
70
+ in:inTransition
71
+ out:outTransition
72
+ type={props.type || 'button'}
73
+ bind:this={div}
74
+ >
75
+ {@render props.children?.()}
76
+ </button>
77
+ {:else}
78
+ <div {...props} in:inTransition out:outTransition bind:this={div}>
79
+ {@render props.children?.()}
80
+ </div>
81
+ {/if}
@@ -0,0 +1,70 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassValue } from 'svelte/elements';
4
+
5
+ export type MarkedTextProps = {
6
+ class?: ClassValue;
7
+ content: string | undefined;
8
+ search: string | undefined;
9
+ element?: 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
10
+ id?: string | undefined;
11
+ children?: Snippet<[{ match: string }]>;
12
+ };
13
+ </script>
14
+
15
+ <script lang="ts">
16
+ let {
17
+ class: clazz = 'shrink-0 whitespace-nowrap text-ellipsis overflow-hidden max-w-full',
18
+ content,
19
+ search,
20
+ element = 'p',
21
+ id,
22
+ children
23
+ }: MarkedTextProps = $props();
24
+
25
+ /**
26
+ * @param str
27
+ * @param search
28
+ * @return tokens: list with {match, prev}, where 'match' matches the search (case-insensitive) and prev is the string between 'match' and the prev 'match' (or start)
29
+ * @return tail: the string after the last match
30
+ */
31
+ const split = (str: string, search: string) => {
32
+ const matchLen = search.length;
33
+ var tokens: { match: string; prev: string }[] = [];
34
+ let pos = str.toLowerCase().search(search.toLowerCase());
35
+ while (pos != -1) {
36
+ tokens.push({
37
+ match: str.slice(pos, pos + matchLen),
38
+ prev: str.slice(0, pos)
39
+ });
40
+ str = str.slice(pos + matchLen);
41
+ pos = str.search(search);
42
+ }
43
+ return {
44
+ tokens,
45
+ tail: str
46
+ };
47
+ };
48
+
49
+ const { tokens, tail } = $derived.by(() => {
50
+ if (!search || !content) return { tokens: [], tail: content };
51
+ return split(content, search);
52
+ });
53
+ </script>
54
+
55
+ <!-- @component
56
+ marks text-parts matching the given search parameter
57
+ -->
58
+ <svelte:element this={element} class={[clazz]} {id}>
59
+ {#each tokens as token (token)}
60
+ {token.prev}
61
+ {#if children}
62
+ {@render children?.({ match: token.match })}
63
+ {:else}
64
+ <mark class="bg-primary-500 text-surface-50 shrink-0 rounded-sm px-px py-0.5">
65
+ {token.match}
66
+ </mark>
67
+ {/if}
68
+ {/each}
69
+ {tail}
70
+ </svelte:element>
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ import { merge } from '$lib/utils/functions';
3
+ import type { ClassValue, HTMLAttributes } from 'svelte/elements';
4
+
5
+ interface Props extends HTMLAttributes<HTMLTextAreaElement> {
6
+ class?: ClassValue;
7
+ value?: string;
8
+ disabled?: boolean;
9
+ placeholder?: string;
10
+ name?: string;
11
+ }
12
+
13
+ let { class: clazz, value = $bindable(), ...rest }: Props = $props();
14
+
15
+ let textareaEl = $state<HTMLTextAreaElement>();
16
+
17
+ function autoResize() {
18
+ if (!textareaEl) return;
19
+ textareaEl.style.height = 'auto';
20
+ textareaEl.style.height = `${textareaEl.scrollHeight}px`;
21
+ }
22
+
23
+ $effect(() => {
24
+ value;
25
+ autoResize();
26
+ });
27
+
28
+ export function focus() {
29
+ textareaEl?.focus();
30
+ }
31
+
32
+ export function isActive() {
33
+ return document.activeElement === textareaEl;
34
+ }
35
+ </script>
36
+
37
+ <textarea
38
+ class={merge(
39
+ 'max-h-96 w-full resize-none overflow-y-auto border-none bg-transparent ring-0 outline-0 transition-all',
40
+ clazz
41
+ )}
42
+ bind:this={textareaEl}
43
+ bind:value
44
+ rows="1"
45
+ {...rest}
46
+ ></textarea>
@@ -7,7 +7,7 @@
7
7
  import type { ClassValue } from 'svelte/elements';
8
8
  import { scale } from 'svelte/transition';
9
9
 
10
- export interface CheckboxProps extends IvoryComponent<HTMLElement> {
10
+ export type CheckboxProps = IvoryComponent<HTMLElement> & {
11
11
  class?: ClassValue;
12
12
  /** `checked` has prioriy over `partial` */
13
13
  checked?: boolean | null;
@@ -17,7 +17,7 @@
17
17
  /** if true, the onclick handler will not be called */
18
18
  disabled?: boolean;
19
19
  onclick?: () => void;
20
- }
20
+ };
21
21
  </script>
22
22
 
23
23
  <!--
@@ -1,4 +1,10 @@
1
- export * from './checkbox/Checkbox.svelte';
2
- export { default as Checkbox } from './checkbox/Checkbox.svelte';
3
- export * from './toggle/Toggle.svelte';
4
- export { default as Toggle } from './toggle/Toggle.svelte';
1
+ export { default as Checkbox, type CheckboxProps } from './checkbox/Checkbox.svelte';
2
+ export {
3
+ default as Element,
4
+ type AnchorAttributes,
5
+ type ButtonAttributes,
6
+ type ElementProps
7
+ } from './Element.svelte';
8
+ export { default as MarkedText, type MarkedTextProps } from './MarkedText.svelte';
9
+ export { default as Textarea } from './Textarea.svelte';
10
+ export { default as Toggle, type ToggleProps } from './toggle/Toggle.svelte';
@@ -4,11 +4,11 @@
4
4
  import type { Snippet } from 'svelte';
5
5
  import type { ClassValue } from 'svelte/elements';
6
6
 
7
- export interface ToggleProps extends IvoryComponent<HTMLElement> {
7
+ export type ToggleProps = IvoryComponent<HTMLElement> & {
8
8
  value?: boolean;
9
9
  class?: ClassValue;
10
10
  children?: Snippet;
11
- }
11
+ };
12
12
  </script>
13
13
 
14
14
  <script lang="ts">
@@ -0,0 +1,23 @@
1
+ <script lang="ts">
2
+ import TextArea from '../basic/Textarea.svelte';
3
+ import Input, { type InputProps } from './Input.svelte';
4
+
5
+ let { ...props }: InputProps<string> = $props();
6
+
7
+ let inputElement = $state<TextArea>();
8
+ export function focus() {
9
+ inputElement?.focus();
10
+ }
11
+ </script>
12
+
13
+ <Input {...props}>
14
+ {#snippet children(inputProps)}
15
+ {@const { name } = props.form.as?.('text')}
16
+ <TextArea
17
+ {...inputProps}
18
+ {name}
19
+ bind:value={props.form.value, props.form.set}
20
+ bind:this={inputElement}
21
+ />
22
+ {/snippet}
23
+ </Input>
@@ -17,5 +17,6 @@ export {
17
17
  export { default as PasswordInput } from './PasswordInput.svelte';
18
18
  export { default as Select } from './select/Select.svelte';
19
19
  export { default as SelectOption } from './select/SelectOption.svelte';
20
+ export { default as TextareaInput } from './TextareaInput.svelte';
20
21
  export { default as TextInput } from './TextInput.svelte';
21
22
  export { default as ToggleInput } from './ToggleInput.svelte';
@@ -3,6 +3,7 @@
3
3
  import { merge } from '$lib/utils/functions';
4
4
  import { type Snippet } from 'svelte';
5
5
  import type { ClassValue } from 'svelte/elements';
6
+ import Element from '../basic/Element.svelte';
6
7
  import type { ColumnConfig } from './columnController.svelte';
7
8
  import { getRowContext } from './Row.svelte';
8
9
  import { getTableContext } from './Table.svelte';
@@ -12,6 +13,7 @@
12
13
  /** If the type is incorrect pass the "row" property with the right type */
13
14
  children: Snippet;
14
15
  onclick?: (e: Event) => void | Promise<void>;
16
+ href?: string;
15
17
  /** Cannot be used with resizable columns*/
16
18
  ignoreWidth?: boolean;
17
19
  offsetNestingLevel?: number;
@@ -21,37 +23,38 @@
21
23
  <script lang="ts">
22
24
  let {
23
25
  class: clazz,
24
- children,
25
26
  onclick,
27
+ href,
26
28
  ignoreWidth = false,
29
+ offsetNestingLevel = 0,
27
30
  // ColumnConfig
31
+ id,
32
+ width,
33
+ minWidth,
28
34
  resizable = true,
29
- offsetNestingLevel = 0,
35
+ header,
30
36
  ...props
31
37
  }: ColumnProps = $props();
32
38
 
33
39
  // Register the new column if this is the first table row that was rendered
34
40
  const tableContext = getTableContext();
35
- const column = tableContext.registerColumn({ resizable, ...props });
41
+ const column = tableContext.registerColumn({ id, width, minWidth, resizable, header });
36
42
  const rowContext = getRowContext();
37
43
 
38
44
  const finalOnClick = $derived(onclick || rowContext.onclick);
39
- const allowClicking = $derived(!!(onclick || rowContext.onclick));
40
-
41
- const element = $derived.by(() => {
42
- if (finalOnClick) return 'button';
43
- if (rowContext.href) return 'a';
44
- return 'div';
45
+ const finalHref = $derived.by(() => {
46
+ if (finalOnClick) return undefined;
47
+ return href || rowContext.href;
45
48
  });
46
49
 
47
50
  // passes updated props to the column
48
51
  $effect(() => {
49
- column.updateConfig({ resizable, ...props });
52
+ column.updateConfig({ resizable, minWidth, id, header });
50
53
  });
51
54
 
52
55
  // this must be separate to the above effect, since otherwise the width would be reset on every scroll
53
56
  $effect(() => {
54
- if (!resizable && typeof props.width !== 'undefined') column.width = props.width;
57
+ if (!resizable && typeof width !== 'undefined') column.width = width;
55
58
  });
56
59
 
57
60
  const widthStyle = $derived(
@@ -60,11 +63,10 @@
60
63
  </script>
61
64
 
62
65
  <!-- svelte-ignore a11y_no_static_element_interactions -->
63
- <svelte:element
64
- this={element}
65
- onclick={allowClicking ? finalOnClick : undefined}
66
- href={!allowClicking ? rowContext.href : undefined}
67
- type={allowClicking ? 'button' : undefined}
66
+ <Element
67
+ {...props}
68
+ onclick={finalOnClick}
69
+ href={finalHref}
68
70
  style={ignoreWidth ? '' : `width: ${widthStyle}`}
69
71
  class={merge([
70
72
  'box-border flex h-full shrink-0 flex-row items-center justify-start gap-1 truncate',
@@ -72,6 +74,4 @@
72
74
  theme.current.table?.column?.class,
73
75
  clazz
74
76
  ])}
75
- >
76
- {@render children()}
77
- </svelte:element>
77
+ />