@svelte-atoms/core 1.0.0-alpha.33 → 1.0.0-alpha.34

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 (125) hide show
  1. package/dist/components/atom/html-atom.svelte +95 -93
  2. package/dist/components/atom/html-atom.svelte.d.ts +1 -1
  3. package/dist/components/button/button.svelte +31 -31
  4. package/dist/components/chip/chip.svelte +41 -0
  5. package/dist/components/chip/chip.svelte.d.ts +6 -0
  6. package/dist/components/chip/index.d.ts +1 -0
  7. package/dist/components/chip/index.js +1 -0
  8. package/dist/components/chip/types.d.ts +11 -0
  9. package/dist/components/chip/types.js +1 -0
  10. package/dist/components/combobox/atoms.d.ts +2 -1
  11. package/dist/components/combobox/atoms.js +2 -1
  12. package/dist/components/combobox/bond.svelte.d.ts +16 -13
  13. package/dist/components/combobox/bond.svelte.js +57 -13
  14. package/dist/components/combobox/combobox-control.svelte +27 -13
  15. package/dist/components/combobox/combobox-control.svelte.d.ts +2 -10
  16. package/dist/components/combobox/combobox-item.svelte +3 -3
  17. package/dist/components/combobox/combobox-root.svelte +65 -65
  18. package/dist/components/combobox/combobox-root.svelte.d.ts +4 -4
  19. package/dist/components/combobox/combobox-selections.svelte +17 -0
  20. package/dist/components/combobox/combobox-selections.svelte.d.ts +4 -0
  21. package/dist/components/combobox/combobox.stories.svelte +25 -12
  22. package/dist/components/combobox/types.d.ts +17 -3
  23. package/dist/components/dropdown/atoms.d.ts +2 -3
  24. package/dist/components/dropdown/atoms.js +3 -3
  25. package/dist/components/dropdown/bond.svelte.d.ts +4 -4
  26. package/dist/components/dropdown/bond.svelte.js +10 -11
  27. package/dist/components/dropdown/dropdown-query.svelte +43 -54
  28. package/dist/components/dropdown/dropdown-query.svelte.d.ts +3 -34
  29. package/dist/components/dropdown/dropdown-root.svelte +15 -2
  30. package/dist/components/dropdown/dropdown-root.svelte.d.ts +4 -16
  31. package/dist/components/dropdown/dropdown-selection.svelte +55 -0
  32. package/dist/components/dropdown/{dropdown-value.svelte.d.ts → dropdown-selection.svelte.d.ts} +5 -15
  33. package/dist/components/dropdown/dropdown-selections.svelte +62 -0
  34. package/dist/components/dropdown/dropdown-selections.svelte.d.ts +5 -0
  35. package/dist/components/dropdown/dropdown.stories.svelte +93 -49
  36. package/dist/components/dropdown/index.d.ts +5 -1
  37. package/dist/components/dropdown/index.js +5 -1
  38. package/dist/components/dropdown/item/controller.svelte.d.ts +1 -1
  39. package/dist/components/dropdown/item/controller.svelte.js +2 -2
  40. package/dist/components/dropdown/item/dropdown-item.svelte +0 -2
  41. package/dist/components/dropdown/runes.svelte.d.ts +6 -2
  42. package/dist/components/dropdown/runes.svelte.js +1 -1
  43. package/dist/components/dropdown/types.d.ts +34 -2
  44. package/dist/components/index.d.ts +2 -0
  45. package/dist/components/index.js +2 -0
  46. package/dist/components/menu/bond.svelte.js +4 -2
  47. package/dist/components/menu/item/controller.svelte.d.ts +1 -0
  48. package/dist/components/menu/item/controller.svelte.js +5 -0
  49. package/dist/components/popover/bond.svelte.js +1 -2
  50. package/dist/components/root/root.css +119 -119
  51. package/dist/components/stepper/README.md +38 -0
  52. package/dist/components/stepper/atoms.d.ts +5 -0
  53. package/dist/components/stepper/atoms.js +5 -0
  54. package/dist/components/stepper/attachments.svelte.d.ts +2 -0
  55. package/dist/components/stepper/attachments.svelte.js +5 -0
  56. package/dist/components/stepper/bond.svelte.d.ts +56 -0
  57. package/dist/components/stepper/bond.svelte.js +99 -0
  58. package/dist/components/stepper/index.d.ts +3 -0
  59. package/dist/components/stepper/index.js +3 -0
  60. package/dist/components/stepper/step/README.md +97 -0
  61. package/dist/components/stepper/step/atoms.d.ts +7 -0
  62. package/dist/components/stepper/step/atoms.js +7 -0
  63. package/dist/components/stepper/step/attachments.svelte.d.ts +2 -0
  64. package/dist/components/stepper/step/attachments.svelte.js +5 -0
  65. package/dist/components/stepper/step/bond.svelte.d.ts +99 -0
  66. package/dist/components/stepper/step/bond.svelte.js +153 -0
  67. package/dist/components/stepper/step/index.d.ts +3 -0
  68. package/dist/components/stepper/step/index.js +2 -0
  69. package/dist/components/stepper/step/step-body.svelte +39 -0
  70. package/dist/components/stepper/step/step-body.svelte.d.ts +26 -0
  71. package/dist/components/stepper/step/step-description.svelte +33 -0
  72. package/dist/components/stepper/step/step-description.svelte.d.ts +26 -0
  73. package/dist/components/stepper/step/step-header.svelte +34 -0
  74. package/dist/components/stepper/step/step-header.svelte.d.ts +26 -0
  75. package/dist/components/stepper/step/step-indicator.svelte +63 -0
  76. package/dist/components/stepper/step/step-indicator.svelte.d.ts +26 -0
  77. package/dist/components/stepper/step/step-root.svelte +42 -0
  78. package/dist/components/stepper/step/step-root.svelte.d.ts +31 -0
  79. package/dist/components/stepper/step/step-separator.svelte +48 -0
  80. package/dist/components/stepper/step/step-separator.svelte.d.ts +26 -0
  81. package/dist/components/stepper/step/step-title.svelte +33 -0
  82. package/dist/components/stepper/step/step-title.svelte.d.ts +26 -0
  83. package/dist/components/stepper/step/types.d.ts +91 -0
  84. package/dist/components/stepper/step/types.js +1 -0
  85. package/dist/components/stepper/stepper-body.svelte +43 -0
  86. package/dist/components/stepper/stepper-body.svelte.d.ts +26 -0
  87. package/dist/components/stepper/stepper-content.svelte +45 -0
  88. package/dist/components/stepper/stepper-content.svelte.d.ts +26 -0
  89. package/dist/components/stepper/stepper-footer.svelte +31 -0
  90. package/dist/components/stepper/stepper-footer.svelte.d.ts +26 -0
  91. package/dist/components/stepper/stepper-header.svelte +39 -0
  92. package/dist/components/stepper/stepper-header.svelte.d.ts +26 -0
  93. package/dist/components/stepper/stepper-root.svelte +60 -0
  94. package/dist/components/stepper/stepper-root.svelte.d.ts +31 -0
  95. package/dist/components/stepper/stepper.stories.svelte +264 -0
  96. package/dist/components/stepper/stepper.stories.svelte.d.ts +4 -0
  97. package/dist/components/stepper/types.d.ts +63 -0
  98. package/dist/components/stepper/types.js +1 -0
  99. package/dist/components/tabs/atoms.d.ts +1 -0
  100. package/dist/components/tabs/atoms.js +1 -0
  101. package/dist/components/tabs/bond.svelte.d.ts +18 -5
  102. package/dist/components/tabs/bond.svelte.js +13 -0
  103. package/dist/components/tabs/tab/bond.svelte.d.ts +7 -7
  104. package/dist/components/tabs/tab/bond.svelte.js +9 -15
  105. package/dist/components/tabs/tab/tab-body.svelte +43 -52
  106. package/dist/components/tabs/tab/tab-description.svelte +33 -41
  107. package/dist/components/tabs/tab/tab-header.svelte +61 -71
  108. package/dist/components/tabs/tab/tab-header.svelte.d.ts +1 -1
  109. package/dist/components/tabs/tab/tab-root.svelte +51 -86
  110. package/dist/components/tabs/tab/tab-root.svelte.d.ts +1 -7
  111. package/dist/components/tabs/tabs-body.svelte +35 -41
  112. package/dist/components/tabs/tabs-body.svelte.d.ts +2 -11
  113. package/dist/components/tabs/tabs-content.svelte +51 -0
  114. package/dist/components/tabs/tabs-content.svelte.d.ts +26 -0
  115. package/dist/components/tabs/tabs-header.svelte +32 -40
  116. package/dist/components/tabs/tabs-header.svelte.d.ts +2 -10
  117. package/dist/components/tabs/tabs-root.svelte +55 -66
  118. package/dist/components/tabs/tabs-root.svelte.d.ts +5 -16
  119. package/dist/components/tabs/tabs.stories.svelte +70 -56
  120. package/dist/components/tabs/types.d.ts +24 -29
  121. package/dist/context/preset.svelte.d.ts +1 -1
  122. package/package.json +33 -6
  123. package/dist/components/dropdown/dropdown-value.svelte +0 -60
  124. package/dist/components/dropdown/dropdown-values.svelte +0 -17
  125. package/dist/components/dropdown/dropdown-values.svelte.d.ts +0 -5
@@ -0,0 +1,264 @@
1
+ <script module>
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+
4
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories
5
+ const { Story } = defineMeta({
6
+ title: 'Atoms/Stepper',
7
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
8
+
9
+ parameters: {
10
+ // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
11
+ layout: 'fullscreen'
12
+ },
13
+ args: {}
14
+ });
15
+ </script>
16
+
17
+ <script lang="ts">
18
+ import { Stepper, Step } from './';
19
+ import { Button } from '../button';
20
+ import { Textarea } from '../textarea';
21
+ import type { StepperBond } from './bond.svelte';
22
+ import { animate } from 'motion'
23
+ import { Stack } from '../stack';
24
+
25
+ const steps = $state([
26
+ {
27
+ header: 'Account Information',
28
+ body: 'Enter your personal details',
29
+ completed: false
30
+ },
31
+ {
32
+ header: 'Address',
33
+ body: 'Provide your shipping address',
34
+ completed: false
35
+ },
36
+ {
37
+ header: 'Payment',
38
+ body: 'Select payment method',
39
+ completed: false
40
+ },
41
+ {
42
+ header: 'Review',
43
+ body: 'Review and confirm',
44
+ optional: true,
45
+ completed: false
46
+ }
47
+ ]);
48
+ let activeStepIndex = $state(0);
49
+
50
+ function handleNext(stepper: StepperBond) {
51
+ stepper.state.navigation.next();
52
+ }
53
+
54
+ function handlePrevious(stepper: StepperBond) {
55
+ stepper.state.navigation.previous();
56
+ }
57
+
58
+ function handleReset(stepper: StepperBond) {
59
+ stepper.state.navigation.reset();
60
+ }
61
+ </script>
62
+
63
+ <Story name="Horizontal" args={{}}>
64
+ <Stepper.Root bind:step= {activeStepIndex} linear={true}>
65
+ {#snippet children({ stepper })}
66
+ <!-- Header: Step indicators -->
67
+ <Stepper.Header class="flex justify-between">
68
+ {#each steps as stepData, i}
69
+ <Step.Root index={i} header={stepData.header} body={stepData.body}>
70
+ {#snippet children({ step })}
71
+ {@const isActive = step?.state?.isActive}
72
+
73
+ <Step.Header class="flex flex-col gap-2 flex-1">
74
+ <div class="flex items-center w-full">
75
+ <Step.Indicator />
76
+ <Step.Separator class="" />
77
+ </div>
78
+
79
+ <div class="flex flex-col pr-4">
80
+ <Step.Title class={isActive
81
+ ? 'text-foreground font-semibold'
82
+ : 'text-muted-foreground'}>
83
+ {stepData?.header}
84
+ {#if stepData?.optional}
85
+ <span class="text-xs">(Optional)</span>
86
+ {/if}
87
+ </Step.Title>
88
+
89
+ <Step.Description class={['text-xs text-muted-foreground']}>
90
+ {stepData?.body}
91
+ </Step.Description>
92
+ </div>
93
+ </Step.Header>
94
+
95
+ <!-- Step Content (shown in Stepper.Body when active) -->
96
+ <Step.Body>
97
+ <h3 class="text-xl font-semibold mb-4">
98
+ Step {i + 1}: {stepData.header}
99
+ </h3>
100
+ <p class="text-muted-foreground mb-6">{stepData.body}</p>
101
+
102
+ <!-- Actual step content would go here -->
103
+ <div class="text-sm text-muted-foreground">
104
+ Content for {stepData.header} step...
105
+ </div>
106
+ </Step.Body>
107
+ {/snippet}
108
+ </Step.Root>
109
+ {/each}
110
+ </Stepper.Header>
111
+
112
+ <!-- Body: Automatically renders active step content -->
113
+ <Stepper.Body class="my-6">
114
+ <Textarea.Root base={Stack.Root} class="overflow-hidden">
115
+ <Stepper.Content
116
+ base={Stack.Item}
117
+ class="min-h-50 flex flex-col p-6"
118
+ enter={(node)=> {
119
+ const duration = 0.4;
120
+ animate(node, { opacity: [0, 1], y: [20, 0] }, { duration });
121
+ return { duration: duration * 1000 };
122
+ }}
123
+ exit={(node)=> {
124
+ const duration = 0.3;
125
+ animate(node, { opacity: [1, 0], y: [0, 0] }, { duration });
126
+ return { duration: duration * 1000 };
127
+ }}
128
+ />
129
+ </Textarea.Root>
130
+ </Stepper.Body>
131
+
132
+ <!-- Footer: Navigation buttons -->
133
+ <Stepper.Footer class="flex justify-between">
134
+ <Button
135
+ variant="outline"
136
+ disabled={stepper.state.isFirstStep}
137
+ onclick={() => handlePrevious(stepper)}
138
+ >
139
+ Previous
140
+ </Button>
141
+
142
+ <div class="flex gap-2">
143
+ <Button variant="ghost" onclick={() => handleReset(stepper)}>Reset</Button>
144
+
145
+ {#if stepper.state.isLastStep}
146
+ <Button onclick={() => alert('Complete!')}>Complete</Button>
147
+ {:else}
148
+ <Button onclick={() => handleNext(stepper)}>Next</Button>
149
+ {/if}
150
+ </div>
151
+ </Stepper.Footer>
152
+ {/snippet}
153
+ </Stepper.Root>
154
+ </Story>
155
+
156
+ <Story name="Vertical" args={{}}>
157
+ <Stepper.Root class="flex gap-4" step={1}>
158
+ {#snippet children({ stepper })}
159
+ <div class="flex gap-4">
160
+ <Stepper.Header class="">
161
+ {#each steps as stepData, i}
162
+ <Step.Root
163
+ index={i}
164
+ header={stepData.header}
165
+ body={stepData.body}
166
+ completed={stepData.completed}
167
+ optional={stepData.optional}
168
+ >
169
+ {#snippet children({ step })}
170
+ <Step.Header class="flex w-full">
171
+ <div class="flex gap-2">
172
+ <div class="flex flex-col">
173
+ <Step.Indicator class="" />
174
+ <Step.Separator class="w-[2px] min-h-10 translate-x-[15px]" />
175
+ </div>
176
+ <div class="flex flex-col">
177
+ <Step.Title>
178
+ {stepData.header}
179
+ {#if stepData.optional}
180
+ <span class="text-xs">(Optional)</span>
181
+ {/if}
182
+ </Step.Title>
183
+
184
+ <Step.Description>
185
+ {stepData}
186
+ </Step.Description>
187
+ </div>
188
+ </div>
189
+
190
+ </Step.Header>
191
+
192
+ <!-- Step Content (shown in Stepper.Body when active) -->
193
+ <Step.Body
194
+ enter={(node)=> {
195
+ const duration = 0.4;
196
+ animate(node, { opacity: [0, 1], y: [20, 0] }, { duration });
197
+ return { duration: duration * 1000 };
198
+ }}
199
+ exit={(node)=> {
200
+ const duration = 0.2;
201
+ animate(node, { opacity: [1, 0], y: [0, 0] }, { duration });
202
+ return { duration: duration * 1000 };
203
+ }}
204
+ >
205
+ <h3 class="text-xl font-semibold mb-4">
206
+ Step {i + 1}: {stepData.header}
207
+ </h3>
208
+ <p class="text-muted-foreground mb-6">{stepData.body}</p>
209
+
210
+ <!-- Actual step content would go here -->
211
+ <div class="text-sm text-muted-foreground">
212
+ Content for {stepData.header} step...
213
+ </div>
214
+ </Step.Body>
215
+ {/snippet}
216
+ </Step.Root>
217
+ {/each}
218
+ </Stepper.Header>
219
+
220
+ <!-- Body: Automatically renders active step content -->
221
+ <Stepper.Body class="h-full">
222
+ <Textarea.Root base={Stack.Root} class="overflow-hidden h-full min-w-96">
223
+ <Stepper.Content
224
+ base={Stack.Item}
225
+ class="min-h-50 flex flex-col p-6"
226
+ enter={(node)=> {
227
+ const duration = 0.4;
228
+ animate(node, { opacity: [0, 1], y: [20, 0] }, { duration });
229
+ return{duration: duration * 1000};
230
+ }}
231
+ exit={(node)=> {
232
+ const duration = 0.3;
233
+ animate(node, { opacity: [1, 0], y: [0, 0] }, { duration });
234
+ return { duration: duration * 1000 };
235
+ }}
236
+ />
237
+ </Textarea.Root>
238
+ </Stepper.Body>
239
+ </div>
240
+
241
+ <Stepper.Footer>
242
+ <div class="flex justify-between">
243
+ <Button
244
+ variant="outline"
245
+ disabled={stepper.state.isFirstStep}
246
+ onclick={() => handlePrevious(stepper)}
247
+ >
248
+ Previous
249
+ </Button>
250
+
251
+ <div class="flex gap-2">
252
+ <Button variant="ghost" onclick={() => handleReset(stepper)}>Reset</Button>
253
+
254
+ {#if stepper.state.isLastStep}
255
+ <Button onclick={() => alert('Complete!')}>Complete</Button>
256
+ {:else}
257
+ <Button onclick={() => handleNext(stepper)}>Next</Button>
258
+ {/if}
259
+ </div>
260
+ </div>
261
+ </Stepper.Footer>
262
+ {/snippet}
263
+ </Stepper.Root>
264
+ </Story>
@@ -0,0 +1,4 @@
1
+ import { Stepper } from './';
2
+ declare const Stepper: import("svelte").Component<Record<string, never>, {}, "">;
3
+ type Stepper = ReturnType<typeof Stepper>;
4
+ export default Stepper;
@@ -0,0 +1,63 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HtmlAtomProps, Base } from '../atom';
3
+ import type { Factory } from '../../types';
4
+ import type { StepperBond } from './bond.svelte';
5
+ export interface StepperRootProps<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> extends Omit<HtmlAtomProps<E, B>, 'children'> {
6
+ /**
7
+ * The active step index (0-based)
8
+ * @bindable
9
+ */
10
+ step?: number;
11
+ /**
12
+ * Whether to enforce linear progression (users can only go to next/previous steps)
13
+ * @default false
14
+ */
15
+ linear?: boolean;
16
+ /**
17
+ * Whether the stepper is disabled
18
+ * @default false
19
+ */
20
+ disabled?: boolean;
21
+ /**
22
+ * Custom factory for creating stepper bond
23
+ */
24
+ factory?: Factory<StepperBond>;
25
+ /**
26
+ * Child render function
27
+ */
28
+ children?: Snippet<[{
29
+ stepper: StepperBond;
30
+ }]>;
31
+ }
32
+ export interface StepperHeaderProps<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> extends Omit<HtmlAtomProps<E, B>, 'children'> {
33
+ /**
34
+ * Child render function
35
+ */
36
+ children?: Snippet<[{
37
+ stepper?: StepperBond;
38
+ }]>;
39
+ }
40
+ export interface StepperBodyProps<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> extends Omit<HtmlAtomProps<E, B>, 'children'> {
41
+ /**
42
+ * Child render function
43
+ */
44
+ children?: Snippet<[{
45
+ stepper?: StepperBond;
46
+ }]>;
47
+ }
48
+ export interface StepperFooterProps<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> extends Omit<HtmlAtomProps<E, B>, 'children'> {
49
+ /**
50
+ * Child render function
51
+ */
52
+ children?: Snippet<[{
53
+ stepper?: StepperBond;
54
+ }]>;
55
+ }
56
+ export interface StepperContentProps<E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base> extends Omit<HtmlAtomProps<E, B>, 'children'> {
57
+ /**
58
+ * Child render function
59
+ */
60
+ children?: Snippet<[{
61
+ stepper?: StepperBond;
62
+ }]>;
63
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,4 @@
1
1
  export { default as Root } from './tabs-root.svelte';
2
2
  export { default as Header } from './tabs-header.svelte';
3
3
  export { default as Body } from './tabs-body.svelte';
4
+ export { default as Content } from './tabs-content.svelte';
@@ -1,3 +1,4 @@
1
1
  export { default as Root } from './tabs-root.svelte';
2
2
  export { default as Header } from './tabs-header.svelte';
3
3
  export { default as Body } from './tabs-body.svelte';
4
+ export { default as Content } from './tabs-content.svelte';
@@ -1,22 +1,29 @@
1
1
  import type { TabBond } from './tab/bond.svelte';
2
- import { Bond, BondState } from '../../shared/bond.svelte';
3
- export type TabsBondProps<T extends Record<string, unknown> = Record<string, unknown>> = {
4
- value?: string;
2
+ import { Bond, BondState, type BondStateProps } from '../../shared/bond.svelte';
3
+ import type { Snippet } from 'svelte';
4
+ export type TabsBondProps<T extends Record<string, unknown> = Record<string, unknown>> = BondStateProps & {
5
+ value?: string | undefined;
5
6
  multiple?: boolean;
6
- extend: T;
7
+ extend?: T;
7
8
  };
8
9
  export type TabElements = {
9
10
  root: HTMLElement;
10
11
  header: HTMLElement;
11
12
  body: HTMLElement;
12
13
  };
14
+ export type TabContentSnippet = {
15
+ props: Record<string, unknown>;
16
+ children: Snippet<[{
17
+ tab?: TabBond;
18
+ }]>;
19
+ };
13
20
  export declare class TabsBond<T = unknown> extends Bond<TabsBondProps, TabsBondState<T>, TabElements> {
14
21
  static CONTEXT_KEY: string;
15
22
  constructor(s: TabsBondState<T>);
16
23
  share(): this;
17
24
  root(props?: Record<string, unknown>): {
18
25
  id: string;
19
- 'aria-orientation': string;
26
+ 'aria-orientation': "horizontal";
20
27
  'data-kind': string;
21
28
  };
22
29
  header(props?: Record<string, unknown>): {
@@ -36,8 +43,14 @@ export declare class TabsBondState<T> extends BondState<TabsBondProps> {
36
43
  #private;
37
44
  constructor(props: () => TabsBondProps);
38
45
  get selectedItem(): TabBond<T>;
46
+ get activeTabContent(): TabContentSnippet | undefined;
39
47
  mountItem<I extends T>(id: string, item: TabBond<I>): () => void;
40
48
  unmountItem(id: string): void;
41
49
  select(id: string): void;
42
50
  unselect(): void;
51
+ registerTabContent(id: string, props: Record<string, unknown>, children: Snippet<[{
52
+ tab?: TabBond;
53
+ }]>): void;
54
+ unregisterTabContent(id: string): void;
55
+ getTab(id: string): TabBond<T> | undefined;
43
56
  }
@@ -62,6 +62,7 @@ export class TabsBond extends Bond {
62
62
  }
63
63
  export class TabsBondState extends BondState {
64
64
  #items = new SvelteMap();
65
+ #tabContents = new SvelteMap();
65
66
  #selectedItem = $derived(this.props?.value ? this.#items.get(this.props?.value) : undefined);
66
67
  constructor(props) {
67
68
  super(props);
@@ -69,6 +70,9 @@ export class TabsBondState extends BondState {
69
70
  get selectedItem() {
70
71
  return this.#selectedItem;
71
72
  }
73
+ get activeTabContent() {
74
+ return this.props?.value ? this.#tabContents.get(this.props.value) : undefined;
75
+ }
72
76
  mountItem(id, item) {
73
77
  if (this.#items.size && !this.props.value) {
74
78
  this.props.value = item.state.props.value;
@@ -85,4 +89,13 @@ export class TabsBondState extends BondState {
85
89
  unselect() {
86
90
  this.props.value = undefined;
87
91
  }
92
+ registerTabContent(id, props, children) {
93
+ this.#tabContents.set(id, { props, children });
94
+ }
95
+ unregisterTabContent(id) {
96
+ this.#tabContents.delete(id);
97
+ }
98
+ getTab(id) {
99
+ return this.#items.get(id);
100
+ }
88
101
  }
@@ -18,11 +18,8 @@ export declare class TabBond<T = unknown> extends Bond<TabBondProps<T>, TabBondS
18
18
  mount(): (() => void) | undefined;
19
19
  unmount(): void;
20
20
  share(): this;
21
- root(props?: Record<string, unknown>): {
22
- 'data-active': boolean;
23
- 'data-kind': string;
24
- };
25
- header(props?: Record<string, unknown>): {
21
+ header(): {
22
+ [x: symbol]: (node: HTMLElement) => (() => void) | undefined;
26
23
  id: string;
27
24
  role: string;
28
25
  'aria-controls': string;
@@ -31,7 +28,8 @@ export declare class TabBond<T = unknown> extends Bond<TabBondProps<T>, TabBondS
31
28
  'data-active': boolean;
32
29
  'data-kind': string;
33
30
  };
34
- body(props?: Record<string, unknown>): {
31
+ body(): {
32
+ [x: symbol]: (node: HTMLElement) => void;
35
33
  id: string;
36
34
  role: string;
37
35
  'aria-labeledby': string;
@@ -40,7 +38,8 @@ export declare class TabBond<T = unknown> extends Bond<TabBondProps<T>, TabBondS
40
38
  'data-active': boolean;
41
39
  'data-kind': string;
42
40
  };
43
- description(props?: Record<string, unknown>): {
41
+ description(): {
42
+ [x: symbol]: (node: HTMLElement) => void;
44
43
  id: string;
45
44
  'data-kind': string;
46
45
  };
@@ -51,6 +50,7 @@ export declare class TabBondState<T> extends BondState<TabBondProps<T>> {
51
50
  #private;
52
51
  constructor(props: () => TabBondProps<T>);
53
52
  get isActive(): boolean;
53
+ get isDisabled(): boolean;
54
54
  select(): void;
55
55
  unselect(): void;
56
56
  }
@@ -5,7 +5,6 @@ import { getElementId } from '../../../utils/dom.svelte';
5
5
  import { portal } from '../../../attachments/portal.svelte';
6
6
  import { Bond, BondState } from '../../../shared/bond.svelte';
7
7
  const TAB_ELEMENTS_KIND = {
8
- root: 'tab-root',
9
8
  header: 'tab-header',
10
9
  body: 'tab-body',
11
10
  description: 'tab-description'
@@ -29,13 +28,7 @@ export class TabBond extends Bond {
29
28
  share() {
30
29
  return TabBond.set(this);
31
30
  }
32
- root(props) {
33
- return {
34
- 'data-active': this.state.isActive,
35
- 'data-kind': 'tab-root'
36
- };
37
- }
38
- header(props) {
31
+ header() {
39
32
  const id = getElementId(this.id, TAB_ELEMENTS_KIND.header);
40
33
  const tabBodyId = getElementId(this.id, TAB_ELEMENTS_KIND.body);
41
34
  return {
@@ -46,7 +39,6 @@ export class TabBond extends Bond {
46
39
  'data-controler-id': this.#tabs?.id,
47
40
  'data-active': this.state.isActive,
48
41
  'data-kind': 'tab-header',
49
- ...props,
50
42
  [createAttachmentKey()]: (node) => {
51
43
  this.elements.header = node;
52
44
  if (!this.#tabs?.elements.header) {
@@ -58,7 +50,7 @@ export class TabBond extends Bond {
58
50
  }
59
51
  };
60
52
  }
61
- body(props) {
53
+ body() {
62
54
  const id = getElementId(this.id, TAB_ELEMENTS_KIND.body);
63
55
  const tabHeaderId = getElementId(this.id, TAB_ELEMENTS_KIND.header);
64
56
  const descriptionId = getElementId(this.id, TAB_ELEMENTS_KIND.description);
@@ -71,18 +63,16 @@ export class TabBond extends Bond {
71
63
  'aria-controledby': tabHeaderId,
72
64
  'data-active': isActive,
73
65
  'data-kind': 'tab-body',
74
- ...props,
75
66
  [createAttachmentKey()]: (node) => {
76
67
  this.elements.body = node;
77
68
  }
78
69
  };
79
70
  }
80
- description(props) {
71
+ description() {
81
72
  const id = getElementId(this.id, TAB_ELEMENTS_KIND.description);
82
73
  return {
83
74
  id,
84
75
  'data-kind': 'tab-description',
85
- ...props,
86
76
  [createAttachmentKey()]: (node) => {
87
77
  this.elements.description = node;
88
78
  }
@@ -96,14 +86,18 @@ export class TabBond extends Bond {
96
86
  }
97
87
  }
98
88
  export class TabBondState extends BondState {
99
- #tabsState;
89
+ #tabsBond;
90
+ #tabsState = $derived(this.#tabsBond?.state);
100
91
  constructor(props) {
101
92
  super(props);
102
- this.#tabsState = TabsBond.get()?.state;
93
+ this.#tabsBond = TabsBond.get();
103
94
  }
104
95
  get isActive() {
105
96
  return this.#tabsState?.props.value === this.props.value;
106
97
  }
98
+ get isDisabled() {
99
+ return this.props.disabled ?? (this.#tabsBond?.elements?.header?.getAttribute?.('aria-disabled') === "true");
100
+ }
107
101
  select() {
108
102
  this.#tabsState?.select(this.props.value);
109
103
  }
@@ -1,52 +1,43 @@
1
- <script lang="ts" generics="E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
2
- import { HtmlAtom, type Base } from '../../atom';
3
- import type { TabBodyProps } from '../types';
4
- import { TabBond } from './bond.svelte';
5
-
6
- const bond = TabBond.get();
7
-
8
- if (!bond) {
9
- throw new Error('TabBody must be used within a Tab');
10
- }
11
-
12
- let {
13
- class: klass = '',
14
- children,
15
- onmount = undefined,
16
- ondestroy = undefined,
17
- animate = undefined,
18
- enter = undefined,
19
- exit = undefined,
20
- initial = undefined,
21
- ...restProps
22
- }: TabBodyProps<E, B> = $props();
23
-
24
- let mounted = $state(false);
25
-
26
- const bodyProps = $derived({
27
- ...bond?.body(),
28
- ...restProps
29
- });
30
-
31
- $effect(() => {
32
- mounted = true;
33
- });
34
- </script>
35
-
36
- <HtmlAtom
37
- preset="tab.body"
38
- class={[
39
- 'tab-body border-border pointer-events-auto flex h-auto w-full min-w-full flex-1 flex-col',
40
- '$preset',
41
- klass
42
- ]}
43
- onmount={onmount?.bind(bond.state)}
44
- ondestroy={ondestroy?.bind(bond.state)}
45
- enter={enter?.bind(bond.state)}
46
- exit={exit?.bind(bond.state)}
47
- initial={initial?.bind(bond.state)}
48
- animate={animate?.bind(bond.state)}
49
- {...bodyProps}
50
- >
51
- {@render children?.({ tab: bond })}
52
- </HtmlAtom>
1
+ <script lang="ts" generics="E extends keyof HTMLElementTagNameMap = 'div', B extends Base = Base">
2
+ import { type Base } from '../../atom';
3
+ import type { TabBodyProps } from '../types';
4
+ import { TabBond } from './bond.svelte';
5
+ import { TabsBond } from '../bond.svelte';
6
+ import { Stack } from '../../stack';
7
+
8
+ const tabBond = TabBond.get();
9
+ const tabsBond = TabsBond.get();
10
+
11
+ if (!tabBond) {
12
+ throw new Error('TabBody must be used within a Tab');
13
+ }
14
+
15
+ let {
16
+ class: klass = '',
17
+ base= Stack.Item,
18
+ children,
19
+ preset = 'tab.body' as const,
20
+ ...restProps
21
+ }: TabBodyProps<E, B> = $props();
22
+
23
+ const contentProps = $derived({
24
+ class: klass,
25
+ preset,
26
+ base,
27
+ ...restProps
28
+ });
29
+
30
+ // Register content snippet with props and children with tabs on mount
31
+ $effect(() => {
32
+ if (tabBond && tabsBond && children) {
33
+ const id = tabBond.state.props.value;
34
+ tabsBond.state.registerTabContent(id, contentProps, children);
35
+
36
+ return () => {
37
+ tabsBond.state.unregisterTabContent(id);
38
+ };
39
+ }
40
+ });
41
+ </script>
42
+
43
+ <!-- Content is teleported to Tabs.Content, so we don't render anything here -->