@hashrytech/quick-components-kit 0.16.8 → 0.17.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @hashrytech/quick-components-kit
2
2
 
3
+ ## 0.17.1
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: adding export for table
8
+
9
+ ## 0.17.0
10
+
11
+ ### Minor Changes
12
+
13
+ - refactor: Updating theme variables for each component and adding table component
14
+
3
15
  ## 0.16.8
4
16
 
5
17
  ### Patch Changes
@@ -20,8 +20,8 @@
20
20
 
21
21
  </script>
22
22
 
23
- <button {disabled} class={twMerge("flex flex-row items-center gap-2 px-4 py-2 bg-button-primary hover:bg-button-primary-hover rounded-primary w-fit cursor-pointer text-white focus:outline-focus-primary",
24
- "disabled:bg-button-primary/60 disabled:cursor-default", props.class)}
23
+ <button {disabled} class={twMerge("flex flex-row items-center gap-2 px-4 py-2 bg-primary-button hover:bg-primary-button-hover rounded-primary w-fit cursor-pointer text-white focus:outline-focus-primary",
24
+ "disabled:bg-primary-button/60 disabled:cursor-default", props.class)}
25
25
  {onclick}>
26
26
  {#if icon}<span class="w-10">{@render icon()}</span>{/if}
27
27
  {#if loadingIcon}<span class="w-10">{@render loadingIcon()}</span>{/if}
@@ -4,26 +4,28 @@
4
4
  import {twMerge} from 'tailwind-merge';
5
5
 
6
6
  export type CheckBoxProps = {
7
- id: string;
8
- name?: string;
9
- label?: string;
10
- disabled?: boolean;
11
- checked?: boolean;
12
- group?: any[];
13
- labelPosition?: "left" | "right";
14
- size?: "sm" | "md" | "lg";
15
- children?: Snippet;
16
- icon?: Snippet;
17
- onclick?: (event: MouseEvent) => void;
18
- labelClass?: ClassNameValue;
19
- class?: ClassNameValue;
7
+ id: string;
8
+ name?: string;
9
+ label?: string;
10
+ disabled?: boolean;
11
+ checked?: boolean;
12
+ value?: any;
13
+ group?: any[];
14
+ labelPosition?: "left" | "right";
15
+ size?: "sm" | "md" | "lg";
16
+ children?: Snippet;
17
+ icon?: Snippet;
18
+ onclick?: (event: Event) => void;
19
+ onchange?: (event: Event) => void;
20
+ labelClass?: ClassNameValue;
21
+ class?: ClassNameValue;
20
22
  };
21
23
 
22
24
  </script>
23
25
 
24
26
  <script lang="ts">
25
27
 
26
- let {id, name, label="", labelPosition="right", checked=$bindable(true), group=$bindable(), size="md", disabled=$bindable(false), onclick, labelClass, ...props}: CheckBoxProps = $props();
28
+ let {id, name, label="", labelPosition="right", checked=$bindable(false), value, group=$bindable(), size="md", disabled=$bindable(false), onclick, onchange, labelClass, ...props}: CheckBoxProps = $props();
27
29
 
28
30
  const sizeMap = {
29
31
  sm: 'w-4 h-4',
@@ -33,9 +35,9 @@
33
35
 
34
36
  </script>
35
37
 
36
- <label for={id} class="inline-flex items-center gap-2 cursor-pointer select-none">
38
+ <label for={id} class="flex items-center gap-2 cursor-pointer select-none">
37
39
  {#if labelPosition === "left"}<span class={twMerge("text-sm", labelClass)}>{label}</span>{/if}
38
- <input {id} name={name ? name : id} type="checkbox" bind:checked bind:group {disabled} class={twMerge("rounded border-border-primary focus:ring-2 ring-focus-primary text-button-primary accent-button-primary cursor-pointer",
39
- sizeMap[size], props.class)} />
40
+ <input {id} name={name ? name : id} type="checkbox" bind:checked {group} {disabled} {value} class={twMerge("rounded focus:ring-2 ring-primary-focus text-primary-input-accent accent-primary-input-accent cursor-pointer",
41
+ checked === true ? "border-primary-input-accent" : "border-primary-input-border", sizeMap[size], props.class)} {onclick} {onchange} />
40
42
  {#if labelPosition === "right"}<span class={twMerge("text-sm", labelClass)}>{label}</span>{/if}
41
43
  </label>
@@ -6,12 +6,14 @@ export type CheckBoxProps = {
6
6
  label?: string;
7
7
  disabled?: boolean;
8
8
  checked?: boolean;
9
+ value?: any;
9
10
  group?: any[];
10
11
  labelPosition?: "left" | "right";
11
12
  size?: "sm" | "md" | "lg";
12
13
  children?: Snippet;
13
14
  icon?: Snippet;
14
- onclick?: (event: MouseEvent) => void;
15
+ onclick?: (event: Event) => void;
16
+ onchange?: (event: Event) => void;
15
17
  labelClass?: ClassNameValue;
16
18
  class?: ClassNameValue;
17
19
  };
@@ -103,7 +103,7 @@ The `<Overlay>` component is used to darken the background and optionally block
103
103
  </script>
104
104
 
105
105
  {#if open}
106
- <div class="">
106
+ <div class="fixed inset-0">
107
107
  <Overlay {transitionDuration} {disableBodyScroll} class={overlayClasses} onclick={() => open = false} />
108
108
  <div role="dialog" aria-modal="true" aria-label={ariaLabel} tabindex="{open ? 0 : -1}" aria-hidden="{!open}"
109
109
  class={twMerge("fixed flex flex-col items-center gap-2 bg-white outline-0 focus:outline-0 active:outline-focus-primary focus:outline-focus-primary overflow-y-auto z-50", postionClasses[position], props.class)}
@@ -1 +1,14 @@
1
+ import type { Component } from 'svelte';
1
2
  export { default as Drawer } from './Drawer.svelte';
3
+ export type DrawerComponent = Component<{
4
+ open?: boolean;
5
+ escapeKeyClose?: boolean;
6
+ disableBodyScroll?: boolean;
7
+ ariaLabel?: string;
8
+ transitionDuration?: number;
9
+ transitionDistance?: number;
10
+ position?: 'left' | 'right' | 'top' | 'bottom';
11
+ overlayClasses?: string;
12
+ class?: string;
13
+ children?: unknown;
14
+ }>;
@@ -20,15 +20,15 @@
20
20
 
21
21
  </script>
22
22
 
23
- <button aria-label={ariaLabel} class={twMerge("px-1 py-0.5 rounded focus:outline-none focus:ring-2 focus:ring-focus-primary cursor-pointer w-fit", props.class)} {onclick}>
23
+ <button aria-label={ariaLabel} class={twMerge("px-1 py-0.5 rounded focus:outline-none focus:ring-2 focus:ring-primary-focus cursor-pointer w-fit", props.class)} {onclick}>
24
24
  <div class={twMerge("flex flex-col items-center justify-center size-7 transition-all gap-2", linesParentClasses)}>
25
25
  <!-- Top bar -->
26
- <span class={twMerge("h-0.5 w-7 bg-button-primary transition-transform duration-300 origin-center", open && useCloseBtn ? "rotate-45 translate-y-2.5" : "", linesClasses)}></span>
26
+ <span class={twMerge("h-0.5 w-7 bg-primary-button transition-transform duration-300 origin-center", open && useCloseBtn ? "rotate-45 translate-y-2.5" : "", linesClasses)}></span>
27
27
 
28
28
  <!-- Middle bar -->
29
- <span class={twMerge("h-0.5 w-7 bg-button-primary transition-opacity duration-300", open && useCloseBtn ? "opacity-0" : "opacity-100", linesClasses)}></span>
29
+ <span class={twMerge("h-0.5 w-7 bg-primary-button transition-opacity duration-300", open && useCloseBtn ? "opacity-0" : "opacity-100", linesClasses)}></span>
30
30
 
31
31
  <!-- Bottom bar -->
32
- <span class={twMerge("h-0.5 w-7 bg-button-primary transition-transform duration-300 origin-center", open && useCloseBtn ? "-rotate-45 -translate-y-2.5" : "", linesClasses)}></span>
32
+ <span class={twMerge("h-0.5 w-7 bg-primary-button transition-transform duration-300 origin-center", open && useCloseBtn ? "-rotate-45 -translate-y-2.5" : "", linesClasses)}></span>
33
33
  </div>
34
34
  </button>
@@ -21,7 +21,7 @@
21
21
  </script>
22
22
 
23
23
  <a {href} data-sveltekit-reload={reload} data-sveltekit-preload-data={preload ? 'hover' : false}
24
- class={twMerge("flex flex-row items-center gap-2 px-4 py-2 bg-button-primary hover:bg-button-primary-hover rounded-primary w-fit cursor-pointer text-white focus:outline-focus-primary", props.class)}>
24
+ class={twMerge("flex flex-row items-center gap-2 px-4 py-2 bg-primary-button hover:bg-primary-button-hover rounded-primary w-fit cursor-pointer text-white focus:outline-focus-primary", props.class)}>
25
25
  {#if icon}<span class="w-10">{@render icon()}</span>{/if}
26
26
  {@render children?.()}
27
27
  </a>
@@ -4,6 +4,7 @@
4
4
  import { fade } from 'svelte/transition';
5
5
  import {twMerge} from 'tailwind-merge';
6
6
  import { disableScroll } from '../../actions/disable-scroll.js';
7
+ import { config } from '../../configs/config.js';
7
8
 
8
9
  export type OverlayProps = {
9
10
  disableBodyScroll?: boolean;
@@ -17,10 +18,10 @@
17
18
  </script>
18
19
 
19
20
  <script lang="ts">
20
- let { disableBodyScroll=true, transitionDuration=100, ariaLabel="Overlay", onclick, children, ...props }: OverlayProps = $props();
21
+ let { disableBodyScroll=true, transitionDuration=config.transitionDuration, ariaLabel="Overlay", onclick, children, ...props }: OverlayProps = $props();
21
22
  </script>
22
23
 
23
- <div transition:fade={{duration: transitionDuration}} class={twMerge("fixed top-0 left-0 right-0 bottom-0 bg-overlay-primary z-40", props.class)} role="presentation" {onclick} use:disableScroll={disableBodyScroll}>
24
+ <div transition:fade={{duration: transitionDuration}} class={twMerge("fixed top-0 left-0 right-0 bottom-0 bg-primary-overlay z-40", props.class)} role="presentation" {onclick} use:disableScroll={disableBodyScroll}>
24
25
  {@render children?.()}
25
26
  </div>
26
27
 
@@ -33,9 +33,11 @@
33
33
 
34
34
  </script>
35
35
 
36
- <label for={id} class="inline-flex items-center gap-2 cursor-pointer select-none">
36
+ <label for={id} class="flex items-center gap-2 cursor-pointer select-none">
37
37
  {#if labelPosition === "left"}<span class={twMerge("text-sm", labelClass)}>{label}</span>{/if}
38
- <input {id} name={name ? name : id} type="radio" bind:value bind:group {disabled} class={twMerge("border-border-primary focus:ring-2 ring-focus-primary text-button-primary accent-button-primary cursor-pointer",
39
- sizeMap[size], props.class)} />
38
+ <input {id} name={name ? name : id} type="radio" {value} bind:group {disabled}
39
+ class={twMerge("focus:ring-2 ring-primary-focus text-primary-input-accent accent-primary-input-accent cursor-pointer",
40
+ group === value ? "border-primary-input-accent" : "border-primary-input-border",
41
+ sizeMap[size], props.class)} {onclick} />
40
42
  {#if labelPosition === "right"}<span class={twMerge("text-sm", labelClass)}>{label}</span>{/if}
41
43
  </label>
@@ -24,7 +24,7 @@
24
24
 
25
25
  <div class={twMerge("flex flex-row flex-wrap gap-4 justify-start xxxs:justify-center items-start py-2 px-4 mt-8 font-semibold", divClasses)}>
26
26
  {#each links as link}
27
- <a class={twMerge("px-4 py-1 hover:border-secondary-500 hover:border-b-2 text-gray-900 bg-transparent hover:bg-transparent rounded-none", link.active ? "border-primary-600 border-b-2": "", props.class)}
27
+ <a class={twMerge("px-4 py-1 hover:border-primary-input-accent/40 hover:border-b-2 text-neutral-800 bg-transparent hover:bg-transparent rounded-none", link.active ? "border-primary-input-accent border-b-2": "", props.class)}
28
28
  data-sveltekit-reload={reload} data-sveltekit-preload-data={preload ? 'hover' : false}
29
29
  href={link.href}>
30
30
  {link.text}
@@ -0,0 +1,226 @@
1
+ <!--
2
+ @component Table
3
+
4
+ A fully responsive, themeable table component for Svelte 5 built with Tailwind CSS.
5
+ Supports both desktop and mobile rendering, multi-select checkboxes, and custom component rendering via `Snippet`.
6
+
7
+ ## Generic
8
+ - `<Table<T>>` — You must pass a `rows` array of type `T[]` and a `getKey(row: T) => string` function.
9
+
10
+ ## Props
11
+
12
+ - `rows: T[]`
13
+ Required. Array of data rows to render.
14
+
15
+ - `getKey: (row: T) => string`
16
+ Required. Function to return a unique key for each row.
17
+
18
+ - `showMultiSelect?: boolean = false`
19
+ If true, displays a checkbox for selecting rows.
20
+
21
+ - `selected?: string[]`
22
+ A list of selected row keys (bindable).
23
+
24
+ - `headings?: Snippet`
25
+ Custom markup or Svelte block for rendering the `<thead>` row.
26
+
27
+ - `tableRow?: Snippet<[T]>`
28
+ Custom markup or Svelte block for rendering each row in desktop view.
29
+
30
+ - `tableRowMobile?: Snippet<[T]>`
31
+ Optional. Enables mobile view by rendering one `<td>` with stacked content.
32
+
33
+ - `class?: ClassNameValue`
34
+ Tailwind classes to apply to the `<table>` element.
35
+
36
+ - `outerDivClass?: ClassNameValue`
37
+ Tailwind classes for the outer scroll wrapper `<div>`.
38
+
39
+ - `headingsRowClass?: ClassNameValue`
40
+ Tailwind classes for the table heading `<tr>`.
41
+
42
+ - `tableRowClass?: ClassNameValue`
43
+ Tailwind classes for each row in desktop view.
44
+
45
+ - `tableRowMobileClass?: ClassNameValue`
46
+ Tailwind classes for each mobile row.
47
+
48
+ - `tableMobileTdClass?: ClassNameValue`
49
+ Tailwind classes for the mobile row's single `<td>` cell.
50
+
51
+ ## Features
52
+
53
+ - Multi-select checkboxes with "select all" support
54
+ - Dual rendering paths for desktop and mobile (controlled by `tableRowMobile`)
55
+ - Sticky selection column (`left-0`)
56
+ - Class merging via `tailwind-merge` to avoid duplicate styles
57
+ - Fully customizable using Svelte `Snippet` syntax
58
+
59
+ ## Example Usage
60
+
61
+ ```svelte
62
+ <Table rows={[ { id: 1, name: "John Doe", age: 30 }, { id: 2, name: "Jane Smith", age: 25 }, { id: 3, name: "Alice Johnson", age: 28 }]} getKey={(u) => u.id.toString()} showMultiSelect={true}>
63
+ {#snippet headings()}
64
+ <TableTd>ID</TableTd>
65
+ <TableTd>Name</TableTd>
66
+ <TableTd>Age</TableTd>
67
+ {/snippet}
68
+
69
+ {#snippet tableRow(row)}
70
+ <TableTd>{row.id}</TableTd>
71
+ <TableTd>{row.name}</TableTd>
72
+ <TableTd>{row.age}</TableTd>
73
+ {/snippet}
74
+
75
+ {#snippet tableRowMobile(row)}
76
+ <div class="flex flex-col gap-2">
77
+ <p class="font-semibold">ID: {row.id}</p>
78
+ <p class="font-semibold">Name: {row.name}</p>
79
+ <p class="font-semibold">Age: {row.age}</p>
80
+ </div>
81
+ {/snippet}
82
+ </Table>
83
+ ```
84
+ -->
85
+
86
+ <script lang="ts" module>
87
+ import type { Snippet } from 'svelte';
88
+ import type { ClassNameValue } from 'tailwind-merge';
89
+
90
+ /**
91
+ * Props for the generic Table component
92
+ * @template T - Type of each row object
93
+ */
94
+ export type TableProps<T> = {
95
+ /** Enable multi-select checkboxes */
96
+ showMultiSelect?: boolean;
97
+
98
+ /** Currently selected row keys */
99
+ selected?: string[];
100
+
101
+ /** Data to render as rows */
102
+ rows: T[];
103
+
104
+ /** Function to extract a unique key for each row */
105
+ getKey: (obj: T) => string;
106
+
107
+ /** Snippet for rendering table headings */
108
+ headings?: Snippet;
109
+
110
+ /** Snippet for rendering a desktop table row */
111
+ tableRow?: Snippet<[T]>;
112
+
113
+ /** Snippet for rendering a mobile table row */
114
+ tableRowMobile?: Snippet<[T]>;
115
+
116
+ /** Snippet for the multi-select checkbox area which should be a TH */
117
+ multiSelectTh?: Snippet;
118
+
119
+ /** Snippet for the multi-select checkbox area which should be a TD */
120
+ multiSelectTd?: Snippet<[T]>;
121
+
122
+ /** Class for the <table> element */
123
+ class?: ClassNameValue;
124
+
125
+ /** Class for the outer <div> wrapper */
126
+ outerDivClass?: ClassNameValue;
127
+
128
+ /** Class for the table headings row */
129
+ headingsRowClass?: ClassNameValue;
130
+
131
+ /** Class for the multi-select checkbox <th> */
132
+ multiSelectThClass?: ClassNameValue;
133
+
134
+ /** Class for each row (desktop) */
135
+ tableRowClass?: ClassNameValue;
136
+
137
+ /** Class for the multi-select checkbox <td> */
138
+ multiSelectTdClass?: ClassNameValue;
139
+
140
+ /** Class for each row (mobile) */
141
+ tableRowMobileClass?: ClassNameValue;
142
+
143
+ /** Class for the <td> cell in mobile view */
144
+ tableMobileTdClass?: ClassNameValue;
145
+ };
146
+ </script>
147
+
148
+ <script lang="ts" generics="T">
149
+ import { twMerge } from "tailwind-merge";
150
+ import {Checkbox} from '../checkbox/index.js';
151
+
152
+ let { showMultiSelect=$bindable(false), selected=$bindable([]), rows=$bindable([]), getKey, headings, tableRow, tableRowMobile, multiSelectTh, multiSelectTd,
153
+ tableMobileTdClass, outerDivClass, headingsRowClass, multiSelectThClass, tableRowClass, multiSelectTdClass, tableRowMobileClass, ...props }: TableProps<T> = $props();
154
+
155
+ function addSelected(rowkey: string){
156
+ if(selected.includes(rowkey)){
157
+ selected = selected.filter((item) => item !== rowkey);
158
+ }else{
159
+ selected.push(rowkey);
160
+ }
161
+ }
162
+
163
+ function handleSelectAll(event: any){
164
+ if (event.target.checked) {
165
+ for(let i = 0; i < rows.length; i++){
166
+ selected.push(getKey(rows[i]));
167
+ }
168
+ }
169
+ else{
170
+ selected = [];
171
+ }
172
+ }
173
+
174
+ </script>
175
+
176
+
177
+ <div class={twMerge("rounded-lg border-primary-table-border w-full overflow-x-auto", tableRowMobile ? "border-0 md:border bg-transparent" : "border bg-white", outerDivClass)}>
178
+ <table class={twMerge("table-fixed w-full text-sm", tableRowMobile ? "border-separate border-spacing-y-2 md:border-collapse md:border-spacing-y-0": "", props.class)} cellpadding="10px">
179
+ <thead class={twMerge("bg-primary-table-heading", tableRowMobile ? "hidden md:table-header-group" : "")}>
180
+ <tr class={twMerge("text-xs text-primary-table-heading-text whitespace-nowrap bg-inherit", headingsRowClass)}>
181
+ {#if showMultiSelect}
182
+ {#if multiSelectTh}
183
+ {@render multiSelectTh()}
184
+ {:else}
185
+ <th class={twMerge("w-12 px-4 py-2 text-center bg-inherit", multiSelectThClass)}>
186
+ <Checkbox id="header-multiselect-checkbox" onchange={handleSelectAll} checked={ rows ? selected.length === rows.length: false} />
187
+ </th>
188
+ {/if}
189
+ {/if}
190
+ {@render headings?.()}
191
+ </tr>
192
+ </thead>
193
+
194
+ <tbody>
195
+ {#each rows as row, index (getKey ? getKey(row) : index)}
196
+ {@const rowKey = getKey(row)}
197
+ {@const isSelected = selected.includes(rowKey)}
198
+
199
+ {#if tableRow}
200
+ <tr class={twMerge("group border-t border-primary-table-border text-primary-table-row-text", tableRowMobile ? "hidden md:table-row" : "",
201
+ tableRowClass, isSelected ? "bg-primary-table-row-selected" : "hover:bg-primary-table-row-hover bg-white")}>
202
+ {#if showMultiSelect}
203
+ {#if multiSelectTd}
204
+ {@render multiSelectTd(row)}
205
+ {:else}
206
+ <td class={twMerge("text-center px-4 py-2 bg-inherit", multiSelectTdClass )}>
207
+ <Checkbox id={"checkbox-" + rowKey} value={rowKey} checked={isSelected} onchange={()=>{addSelected(rowKey)}} />
208
+ </td>
209
+ {/if}
210
+ {/if}
211
+ {@render tableRow?.(row)}
212
+ </tr>
213
+ {/if}
214
+
215
+ {#if tableRowMobile}
216
+ <tr class={twMerge("md:hidden text-primary-table-row-text", isSelected ? "bg-primary-table-row-selected" : "bg-white", tableRowMobileClass)}>
217
+ <td class={twMerge("border border-primary-table-border border-t-4 rounded-primary px-2 pb-2 relative bg-inherit", tableMobileTdClass)}>
218
+ {#if showMultiSelect}<button onclick={()=>{ addSelected(rowKey)}} aria-label="select row" class="absolute inset-0 cursor-pointer"></button>{/if}
219
+ {@render tableRowMobile?.(row)}
220
+ </td>
221
+ </tr>
222
+ {/if}
223
+ {/each}
224
+ </tbody>
225
+ </table>
226
+ </div>
@@ -0,0 +1,143 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassNameValue } from 'tailwind-merge';
3
+ /**
4
+ * Props for the generic Table component
5
+ * @template T - Type of each row object
6
+ */
7
+ export type TableProps<T> = {
8
+ /** Enable multi-select checkboxes */
9
+ showMultiSelect?: boolean;
10
+ /** Currently selected row keys */
11
+ selected?: string[];
12
+ /** Data to render as rows */
13
+ rows: T[];
14
+ /** Function to extract a unique key for each row */
15
+ getKey: (obj: T) => string;
16
+ /** Snippet for rendering table headings */
17
+ headings?: Snippet;
18
+ /** Snippet for rendering a desktop table row */
19
+ tableRow?: Snippet<[T]>;
20
+ /** Snippet for rendering a mobile table row */
21
+ tableRowMobile?: Snippet<[T]>;
22
+ /** Snippet for the multi-select checkbox area which should be a TH */
23
+ multiSelectTh?: Snippet;
24
+ /** Snippet for the multi-select checkbox area which should be a TD */
25
+ multiSelectTd?: Snippet<[T]>;
26
+ /** Class for the <table> element */
27
+ class?: ClassNameValue;
28
+ /** Class for the outer <div> wrapper */
29
+ outerDivClass?: ClassNameValue;
30
+ /** Class for the table headings row */
31
+ headingsRowClass?: ClassNameValue;
32
+ /** Class for the multi-select checkbox <th> */
33
+ multiSelectThClass?: ClassNameValue;
34
+ /** Class for each row (desktop) */
35
+ tableRowClass?: ClassNameValue;
36
+ /** Class for the multi-select checkbox <td> */
37
+ multiSelectTdClass?: ClassNameValue;
38
+ /** Class for each row (mobile) */
39
+ tableRowMobileClass?: ClassNameValue;
40
+ /** Class for the <td> cell in mobile view */
41
+ tableMobileTdClass?: ClassNameValue;
42
+ };
43
+ declare class __sveltets_Render<T> {
44
+ props(): TableProps<T>;
45
+ events(): {};
46
+ slots(): {};
47
+ bindings(): "showMultiSelect" | "selected" | "rows";
48
+ exports(): {};
49
+ }
50
+ interface $$IsomorphicComponent {
51
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
52
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
53
+ } & ReturnType<__sveltets_Render<T>['exports']>;
54
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
55
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
56
+ }
57
+ /**
58
+ * Table
59
+ *
60
+ * A fully responsive, themeable table component for Svelte 5 built with Tailwind CSS.
61
+ * Supports both desktop and mobile rendering, multi-select checkboxes, and custom component rendering via `Snippet`.
62
+ *
63
+ * ## Generic
64
+ * - `<Table<T>>` — You must pass a `rows` array of type `T[]` and a `getKey(row: T) => string` function.
65
+ *
66
+ * ## Props
67
+ *
68
+ * - `rows: T[]`
69
+ * Required. Array of data rows to render.
70
+ *
71
+ * - `getKey: (row: T) => string`
72
+ * Required. Function to return a unique key for each row.
73
+ *
74
+ * - `showMultiSelect?: boolean = false`
75
+ * If true, displays a checkbox for selecting rows.
76
+ *
77
+ * - `selected?: string[]`
78
+ * A list of selected row keys (bindable).
79
+ *
80
+ * - `headings?: Snippet`
81
+ * Custom markup or Svelte block for rendering the `<thead>` row.
82
+ *
83
+ * - `tableRow?: Snippet<[T]>`
84
+ * Custom markup or Svelte block for rendering each row in desktop view.
85
+ *
86
+ * - `tableRowMobile?: Snippet<[T]>`
87
+ * Optional. Enables mobile view by rendering one `<td>` with stacked content.
88
+ *
89
+ * - `class?: ClassNameValue`
90
+ * Tailwind classes to apply to the `<table>` element.
91
+ *
92
+ * - `outerDivClass?: ClassNameValue`
93
+ * Tailwind classes for the outer scroll wrapper `<div>`.
94
+ *
95
+ * - `headingsRowClass?: ClassNameValue`
96
+ * Tailwind classes for the table heading `<tr>`.
97
+ *
98
+ * - `tableRowClass?: ClassNameValue`
99
+ * Tailwind classes for each row in desktop view.
100
+ *
101
+ * - `tableRowMobileClass?: ClassNameValue`
102
+ * Tailwind classes for each mobile row.
103
+ *
104
+ * - `tableMobileTdClass?: ClassNameValue`
105
+ * Tailwind classes for the mobile row's single `<td>` cell.
106
+ *
107
+ * ## Features
108
+ *
109
+ * - Multi-select checkboxes with "select all" support
110
+ * - Dual rendering paths for desktop and mobile (controlled by `tableRowMobile`)
111
+ * - Sticky selection column (`left-0`)
112
+ * - Class merging via `tailwind-merge` to avoid duplicate styles
113
+ * - Fully customizable using Svelte `Snippet` syntax
114
+ *
115
+ * ## Example Usage
116
+ *
117
+ * ```svelte
118
+ * <Table rows={[ { id: 1, name: "John Doe", age: 30 }, { id: 2, name: "Jane Smith", age: 25 }, { id: 3, name: "Alice Johnson", age: 28 }]} getKey={(u) => u.id.toString()} showMultiSelect={true}>
119
+ * {#snippet headings()}
120
+ * <TableTd>ID</TableTd>
121
+ * <TableTd>Name</TableTd>
122
+ * <TableTd>Age</TableTd>
123
+ * {/snippet}
124
+ *
125
+ * {#snippet tableRow(row)}
126
+ * <TableTd>{row.id}</TableTd>
127
+ * <TableTd>{row.name}</TableTd>
128
+ * <TableTd>{row.age}</TableTd>
129
+ * {/snippet}
130
+ *
131
+ * {#snippet tableRowMobile(row)}
132
+ * <div class="flex flex-col gap-2">
133
+ * <p class="font-semibold">ID: {row.id}</p>
134
+ * <p class="font-semibold">Name: {row.name}</p>
135
+ * <p class="font-semibold">Age: {row.age}</p>
136
+ * </div>
137
+ * {/snippet}
138
+ * </Table>
139
+ * ```
140
+ */
141
+ declare const Table: $$IsomorphicComponent;
142
+ type Table<T> = InstanceType<typeof Table<T>>;
143
+ export default Table;
@@ -0,0 +1,19 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassNameValue } from 'tailwind-merge';
4
+
5
+ export type TableColProps = {
6
+ children: Snippet
7
+ class?: ClassNameValue;
8
+ };
9
+
10
+ </script>
11
+
12
+ <script lang="ts">
13
+ import { twMerge } from "tailwind-merge";
14
+
15
+ let { children, ...props }: TableColProps = $props();
16
+
17
+ </script>
18
+
19
+ <td class={twMerge("text-left align-middle p-2.5 bg-inherit", props.class)}>{@render children?.()}</td>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassNameValue } from 'tailwind-merge';
3
+ export type TableColProps = {
4
+ children: Snippet;
5
+ class?: ClassNameValue;
6
+ };
7
+ declare const TableTd: import("svelte").Component<TableColProps, {}, "">;
8
+ type TableTd = ReturnType<typeof TableTd>;
9
+ export default TableTd;
@@ -0,0 +1,19 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from 'svelte';
3
+ import type { ClassNameValue } from 'tailwind-merge';
4
+
5
+ export type TableThProps = {
6
+ children: Snippet
7
+ class?: ClassNameValue;
8
+ };
9
+
10
+ </script>
11
+
12
+ <script lang="ts">
13
+ import { twMerge } from "tailwind-merge";
14
+
15
+ let { children, ...props }: TableThProps = $props();
16
+
17
+ </script>
18
+
19
+ <th scope="col" class={twMerge("p-3 text-left uppercase font-semibold", props.class)}>{@render children?.()}</th>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassNameValue } from 'tailwind-merge';
3
+ export type TableThProps = {
4
+ children: Snippet;
5
+ class?: ClassNameValue;
6
+ };
7
+ declare const TableTh: import("svelte").Component<TableThProps, {}, "">;
8
+ type TableTh = ReturnType<typeof TableTh>;
9
+ export default TableTh;
@@ -0,0 +1,3 @@
1
+ export { default as Table } from './Table.svelte';
2
+ export { default as TableTd } from './TableTd.svelte';
3
+ export { default as TableTh } from './TableTh.svelte';
@@ -0,0 +1,3 @@
1
+ export { default as Table } from './Table.svelte';
2
+ export { default as TableTd } from './TableTd.svelte';
3
+ export { default as TableTh } from './TableTh.svelte';
@@ -69,12 +69,12 @@
69
69
  </script>
70
70
 
71
71
  <div class="flex flex-col gap-1 w-full">
72
- {#if label}{@render label()}{:else}{#if labelText}<label for={id} class="text-sm font-medium text-neutral-600 ml-1">{labelText}</label>{/if}{/if}
72
+ {#if label}{@render label()}{:else}{#if labelText}<label for={id} class="text-sm font-medium text-primary-label-text ml-1">{labelText}</label>{/if}{/if}
73
73
  <div class="relative">
74
74
  {#if icon}<div class="absolute inset-y-0 left-0 flex items-center justify-center rounded-l-primary m-0.5 w-10">{@render icon()}</div>{/if}
75
75
  <input {disabled} {required} {type} {id} name={name ? name: id} {placeholder} {onchange} {onmouseup} bind:value
76
- class={twMerge("rounded-primary border-border-primary focus:border-primary-500 focus:ring-primary-500 placeholder:opacity-50 disabled:bg-neutral-300/30 disabled:border-gray-300/30",
77
- error ? "bg-red-50 border-red-300 ring-red-300" : "",
76
+ class={twMerge("rounded-primary border-primary-input-border focus:border-primary-focus focus:ring-primary-focus placeholder:opacity-50 disabled:bg-neutral-300/30 disabled:border-neutral-300/30",
77
+ error ? "bg-red-50 border-red-300" : "",
78
78
  icon ? "pl-10" : "",
79
79
  sizeStyle[size], props.class)}
80
80
  />
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from './components/radio/index.js';
9
9
  export * from './components/checkbox/index.js';
10
10
  export * from './components/tab-navigation/index.js';
11
11
  export * from './components/portal/index.js';
12
+ export * from './components/table/index.js';
12
13
  export * from './actions/disable-scroll.js';
13
14
  export * from './actions/on-keydown.js';
14
15
  export * from './actions/lock-scroll.js';
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ export * from './components/radio/index.js';
11
11
  export * from './components/checkbox/index.js';
12
12
  export * from './components/tab-navigation/index.js';
13
13
  export * from './components/portal/index.js';
14
+ export * from './components/table/index.js';
14
15
  export * from './actions/disable-scroll.js';
15
16
  export * from './actions/on-keydown.js';
16
17
  export * from './actions/lock-scroll.js';
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/hashrytech/quick-components-kit.git"
7
7
  },
8
- "version": "0.16.8",
8
+ "version": "0.17.1",
9
9
  "license": "MIT",
10
10
  "author": "Hashry Tech",
11
11
  "files": [