svelte-ag 1.2.3 → 1.2.4

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.
@@ -0,0 +1,41 @@
1
+ <script lang="ts">
2
+ import { Search } from '../index.js';
3
+
4
+ let {
5
+ items,
6
+ value = $bindable(),
7
+ rootClass,
8
+ rootTestId,
9
+ inputClass,
10
+ inputLabel,
11
+ inputTestId,
12
+ listClass,
13
+ listTestId,
14
+ paginationClass,
15
+ paginationTestId,
16
+ perPage = $bindable(1)
17
+ }: {
18
+ items: Search.RootProps['items'];
19
+ value: Search.RootProps['value'];
20
+ rootClass?: string;
21
+ rootTestId?: string;
22
+ inputClass?: string;
23
+ inputLabel?: string;
24
+ inputTestId?: string;
25
+ listClass?: string;
26
+ listTestId?: string;
27
+ paginationClass?: string;
28
+ paginationTestId?: string;
29
+ perPage?: Search.PagnationProps['perPage'];
30
+ } = $props();
31
+ </script>
32
+
33
+ {#snippet itemSnippet(item: NonNullable<Search.RootProps['items']>[number])}
34
+ <span>{item.label}</span>
35
+ {/snippet}
36
+
37
+ <Search.Root {items} bind:value class={rootClass} data-testid={rootTestId}>
38
+ <Search.Input class={inputClass} aria-label={inputLabel} data-testid={inputTestId} />
39
+ <Search.List item={itemSnippet} class={listClass} data-testid={listTestId} />
40
+ <Search.Pagnation bind:perPage class={paginationClass} data-testid={paginationTestId} />
41
+ </Search.Root>
@@ -0,0 +1,19 @@
1
+ import { Search } from '../index.js';
2
+ type $$ComponentProps = {
3
+ items: Search.RootProps['items'];
4
+ value: Search.RootProps['value'];
5
+ rootClass?: string;
6
+ rootTestId?: string;
7
+ inputClass?: string;
8
+ inputLabel?: string;
9
+ inputTestId?: string;
10
+ listClass?: string;
11
+ listTestId?: string;
12
+ paginationClass?: string;
13
+ paginationTestId?: string;
14
+ perPage?: Search.PagnationProps['perPage'];
15
+ };
16
+ declare const SearchPassthroughHarness: import("svelte").Component<$$ComponentProps, {}, "value" | "perPage">;
17
+ type SearchPassthroughHarness = ReturnType<typeof SearchPassthroughHarness>;
18
+ export default SearchPassthroughHarness;
19
+ //# sourceMappingURL=SearchPassthroughHarness.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchPassthroughHarness.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/search/combinations/SearchPassthroughHarness.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEpC,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;CAC5C,CAAC;AAgCJ,QAAA,MAAM,wBAAwB,uEAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=searchPassthrough.comp.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchPassthrough.comp.test.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/search/combinations/searchPassthrough.comp.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { render, screen } from '@testing-library/svelte';
2
+ import { describe, expect, it } from 'vitest';
3
+ import SearchPassthroughHarness from './SearchPassthroughHarness.svelte';
4
+ const items = [
5
+ { label: 'Alpha', value: 'alpha' },
6
+ { label: 'Beta', value: 'beta' }
7
+ ];
8
+ describe('Search passthrough props', () => {
9
+ it('forwards root class and data attributes', () => {
10
+ render(SearchPassthroughHarness, {
11
+ props: {
12
+ items,
13
+ value: items[0],
14
+ rootClass: 'root-class',
15
+ rootTestId: 'search-root'
16
+ }
17
+ });
18
+ const root = screen.getByTestId('search-root');
19
+ expect(root.className).toContain('root-class');
20
+ expect(root.getAttribute('data-search-root')).toBe('');
21
+ });
22
+ it('forwards input class and aria attributes', () => {
23
+ render(SearchPassthroughHarness, {
24
+ props: {
25
+ items,
26
+ value: items[0],
27
+ inputClass: 'input-class',
28
+ inputLabel: 'Filter items',
29
+ inputTestId: 'search-input'
30
+ }
31
+ });
32
+ const input = screen.getByTestId('search-input');
33
+ expect(input.className).toContain('input-class');
34
+ expect(input.getAttribute('aria-label')).toBe('Filter items');
35
+ expect(input.getAttribute('data-search-input')).toBe('');
36
+ });
37
+ it('forwards list class and data attributes to the list container', () => {
38
+ render(SearchPassthroughHarness, {
39
+ props: {
40
+ items,
41
+ value: items[0],
42
+ listClass: 'list-class',
43
+ listTestId: 'search-list'
44
+ }
45
+ });
46
+ const list = screen.getByTestId('search-list');
47
+ const itemButton = screen.getByRole('button', { name: 'Alpha' });
48
+ expect(list.className).toContain('list-class');
49
+ expect(list.getAttribute('data-search-list')).toBe('');
50
+ expect(itemButton.className).not.toContain('list-class');
51
+ });
52
+ it('forwards pagination class and data attributes to the pagination root', () => {
53
+ render(SearchPassthroughHarness, {
54
+ props: {
55
+ items,
56
+ value: items[0],
57
+ paginationClass: 'pagination-class',
58
+ paginationTestId: 'search-pagination'
59
+ }
60
+ });
61
+ const pagination = screen.getByTestId('search-pagination');
62
+ expect(pagination.className).toContain('pagination-class');
63
+ expect(pagination.getAttribute('data-search-item')).toBe('');
64
+ });
65
+ });
@@ -22,4 +22,15 @@ describe('SearchPopover', () => {
22
22
  const trigger = screen.getByRole('combobox');
23
23
  expect(trigger.className).toContain('consumer-class');
24
24
  });
25
+ it('forwards non-class trigger props to the real popover trigger button', () => {
26
+ render(SearchPopover, {
27
+ props: {
28
+ disabled: true,
29
+ item: itemSnippet,
30
+ items: [selectedItem],
31
+ value: selectedItem
32
+ }
33
+ });
34
+ expect(screen.getByRole('combobox')).toHaveProperty('disabled', true);
35
+ });
25
36
  });
@@ -8,7 +8,15 @@
8
8
  import { useSearchList } from '../search.svelte';
9
9
  import type { SearchListProps } from '../types';
10
10
 
11
- let { children, child, id = useId(), ref = $bindable(null), item, ...restProps }: SearchListProps = $props();
11
+ let {
12
+ children,
13
+ child,
14
+ class: className,
15
+ id = useId(),
16
+ ref = $bindable(null),
17
+ item,
18
+ ...restProps
19
+ }: SearchListProps = $props();
12
20
 
13
21
  const listState = useSearchList({
14
22
  id: box.with(() => id),
@@ -24,7 +32,7 @@
24
32
  {#if child}
25
33
  {@render child({ props: mergedProps })}
26
34
  {:else}
27
- <div {...mergedProps} class="grid w-full auto-rows-fr px-2">
35
+ <div {...mergedProps} class={cn('grid w-full auto-rows-fr px-2', className)}>
28
36
  {#each listState.suggestions as listItem (listItem.value)}
29
37
  <Button
30
38
  variant="ghost"
@@ -34,8 +42,7 @@
34
42
  hover:bg-muted
35
43
  `,
36
44
  listState.selected(listItem) && 'bg-muted',
37
- listState.visible(listItem) ? '' : 'hidden!',
38
- mergedProps.class
45
+ listState.visible(listItem) ? '' : 'hidden!'
39
46
  )}
40
47
  onclick={() => listState.select(listItem)}
41
48
  >
@@ -1 +1 @@
1
- {"version":3,"file":"search-list.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/search/components/search-list.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAiDhD,QAAA,MAAM,UAAU,wDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"search-list.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/search/components/search-list.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAwDhD,QAAA,MAAM,UAAU,wDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -3,12 +3,14 @@
3
3
  import { box, mergeProps } from 'svelte-toolbelt';
4
4
 
5
5
  import * as Pagination from '$shadcn/pagination/index.js';
6
+ import { cn } from '../../../utils/index.js';
6
7
 
7
8
  import { useSearchPagnation } from '../search.svelte';
8
9
  import type { SearchPagnationProps } from '../types';
9
10
 
10
11
  let {
11
12
  child,
13
+ class: className,
12
14
  id = useId(),
13
15
  ref = $bindable(null),
14
16
  page = $bindable(1),
@@ -40,7 +42,13 @@
40
42
  {#if child}
41
43
  {@render child({ props: mergedProps })}
42
44
  {:else}
43
- <Pagination.Root class="pb-2" count={pagnationState.length} perPage={pagnationState.perPage} bind:page>
45
+ <Pagination.Root
46
+ {...mergedProps}
47
+ class={cn('pb-2', className)}
48
+ count={pagnationState.length}
49
+ perPage={pagnationState.perPage}
50
+ bind:page
51
+ >
44
52
  {#snippet children({ pages, currentPage })}
45
53
  <Pagination.Content>
46
54
  <Pagination.Item>
@@ -1 +1 @@
1
- {"version":3,"file":"search-pagnation.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/search/components/search-pagnation.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAyErD,QAAA,MAAM,eAAe;;;;8BAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"search-pagnation.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/search/components/search-pagnation.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AA2ErD,QAAA,MAAM,eAAe;;;;8BAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-ag",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "Useful svelte components",
5
5
  "bugs": "https://github.com/ageorgeh/svelte-ag/issues",
6
6
  "author": "Alexander Hornung",
@@ -0,0 +1,41 @@
1
+ <script lang="ts">
2
+ import { Search } from '../index.js';
3
+
4
+ let {
5
+ items,
6
+ value = $bindable(),
7
+ rootClass,
8
+ rootTestId,
9
+ inputClass,
10
+ inputLabel,
11
+ inputTestId,
12
+ listClass,
13
+ listTestId,
14
+ paginationClass,
15
+ paginationTestId,
16
+ perPage = $bindable(1)
17
+ }: {
18
+ items: Search.RootProps['items'];
19
+ value: Search.RootProps['value'];
20
+ rootClass?: string;
21
+ rootTestId?: string;
22
+ inputClass?: string;
23
+ inputLabel?: string;
24
+ inputTestId?: string;
25
+ listClass?: string;
26
+ listTestId?: string;
27
+ paginationClass?: string;
28
+ paginationTestId?: string;
29
+ perPage?: Search.PagnationProps['perPage'];
30
+ } = $props();
31
+ </script>
32
+
33
+ {#snippet itemSnippet(item: NonNullable<Search.RootProps['items']>[number])}
34
+ <span>{item.label}</span>
35
+ {/snippet}
36
+
37
+ <Search.Root {items} bind:value class={rootClass} data-testid={rootTestId}>
38
+ <Search.Input class={inputClass} aria-label={inputLabel} data-testid={inputTestId} />
39
+ <Search.List item={itemSnippet} class={listClass} data-testid={listTestId} />
40
+ <Search.Pagnation bind:perPage class={paginationClass} data-testid={paginationTestId} />
41
+ </Search.Root>
@@ -0,0 +1,79 @@
1
+ import { render, screen } from '@testing-library/svelte';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import SearchPassthroughHarness from './SearchPassthroughHarness.svelte';
5
+
6
+ const items = [
7
+ { label: 'Alpha', value: 'alpha' },
8
+ { label: 'Beta', value: 'beta' }
9
+ ];
10
+
11
+ describe('Search passthrough props', () => {
12
+ it('forwards root class and data attributes', () => {
13
+ render(SearchPassthroughHarness, {
14
+ props: {
15
+ items,
16
+ value: items[0],
17
+ rootClass: 'root-class',
18
+ rootTestId: 'search-root'
19
+ }
20
+ });
21
+
22
+ const root = screen.getByTestId('search-root');
23
+
24
+ expect(root.className).toContain('root-class');
25
+ expect(root.getAttribute('data-search-root')).toBe('');
26
+ });
27
+
28
+ it('forwards input class and aria attributes', () => {
29
+ render(SearchPassthroughHarness, {
30
+ props: {
31
+ items,
32
+ value: items[0],
33
+ inputClass: 'input-class',
34
+ inputLabel: 'Filter items',
35
+ inputTestId: 'search-input'
36
+ }
37
+ });
38
+
39
+ const input = screen.getByTestId('search-input');
40
+
41
+ expect(input.className).toContain('input-class');
42
+ expect(input.getAttribute('aria-label')).toBe('Filter items');
43
+ expect(input.getAttribute('data-search-input')).toBe('');
44
+ });
45
+
46
+ it('forwards list class and data attributes to the list container', () => {
47
+ render(SearchPassthroughHarness, {
48
+ props: {
49
+ items,
50
+ value: items[0],
51
+ listClass: 'list-class',
52
+ listTestId: 'search-list'
53
+ }
54
+ });
55
+
56
+ const list = screen.getByTestId('search-list');
57
+ const itemButton = screen.getByRole('button', { name: 'Alpha' });
58
+
59
+ expect(list.className).toContain('list-class');
60
+ expect(list.getAttribute('data-search-list')).toBe('');
61
+ expect(itemButton.className).not.toContain('list-class');
62
+ });
63
+
64
+ it('forwards pagination class and data attributes to the pagination root', () => {
65
+ render(SearchPassthroughHarness, {
66
+ props: {
67
+ items,
68
+ value: items[0],
69
+ paginationClass: 'pagination-class',
70
+ paginationTestId: 'search-pagination'
71
+ }
72
+ });
73
+
74
+ const pagination = screen.getByTestId('search-pagination');
75
+
76
+ expect(pagination.className).toContain('pagination-class');
77
+ expect(pagination.getAttribute('data-search-item')).toBe('');
78
+ });
79
+ });
@@ -28,4 +28,17 @@ describe('SearchPopover', () => {
28
28
 
29
29
  expect(trigger.className).toContain('consumer-class');
30
30
  });
31
+
32
+ it('forwards non-class trigger props to the real popover trigger button', () => {
33
+ render(SearchPopover, {
34
+ props: {
35
+ disabled: true,
36
+ item: itemSnippet,
37
+ items: [selectedItem],
38
+ value: selectedItem
39
+ }
40
+ });
41
+
42
+ expect(screen.getByRole('combobox')).toHaveProperty('disabled', true);
43
+ });
31
44
  });
@@ -8,7 +8,15 @@
8
8
  import { useSearchList } from '../search.svelte';
9
9
  import type { SearchListProps } from '../types';
10
10
 
11
- let { children, child, id = useId(), ref = $bindable(null), item, ...restProps }: SearchListProps = $props();
11
+ let {
12
+ children,
13
+ child,
14
+ class: className,
15
+ id = useId(),
16
+ ref = $bindable(null),
17
+ item,
18
+ ...restProps
19
+ }: SearchListProps = $props();
12
20
 
13
21
  const listState = useSearchList({
14
22
  id: box.with(() => id),
@@ -24,7 +32,7 @@
24
32
  {#if child}
25
33
  {@render child({ props: mergedProps })}
26
34
  {:else}
27
- <div {...mergedProps} class="grid w-full auto-rows-fr px-2">
35
+ <div {...mergedProps} class={cn('grid w-full auto-rows-fr px-2', className)}>
28
36
  {#each listState.suggestions as listItem (listItem.value)}
29
37
  <Button
30
38
  variant="ghost"
@@ -34,8 +42,7 @@
34
42
  hover:bg-muted
35
43
  `,
36
44
  listState.selected(listItem) && 'bg-muted',
37
- listState.visible(listItem) ? '' : 'hidden!',
38
- mergedProps.class
45
+ listState.visible(listItem) ? '' : 'hidden!'
39
46
  )}
40
47
  onclick={() => listState.select(listItem)}
41
48
  >
@@ -3,12 +3,14 @@
3
3
  import { box, mergeProps } from 'svelte-toolbelt';
4
4
 
5
5
  import * as Pagination from '$shadcn/pagination/index.js';
6
+ import { cn } from '$utils/index.js';
6
7
 
7
8
  import { useSearchPagnation } from '../search.svelte';
8
9
  import type { SearchPagnationProps } from '../types';
9
10
 
10
11
  let {
11
12
  child,
13
+ class: className,
12
14
  id = useId(),
13
15
  ref = $bindable(null),
14
16
  page = $bindable(1),
@@ -40,7 +42,13 @@
40
42
  {#if child}
41
43
  {@render child({ props: mergedProps })}
42
44
  {:else}
43
- <Pagination.Root class="pb-2" count={pagnationState.length} perPage={pagnationState.perPage} bind:page>
45
+ <Pagination.Root
46
+ {...mergedProps}
47
+ class={cn('pb-2', className)}
48
+ count={pagnationState.length}
49
+ perPage={pagnationState.perPage}
50
+ bind:page
51
+ >
44
52
  {#snippet children({ pages, currentPage })}
45
53
  <Pagination.Content>
46
54
  <Pagination.Item>