@dvcol/neo-svelte 0.1.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.
Files changed (163) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/LICENSE +21 -0
  3. package/README.md +89 -0
  4. package/dist/assets/neo-icon-resizer-bottom-right.svg +5 -0
  5. package/dist/buttons/NeoButton.svelte +466 -0
  6. package/dist/buttons/NeoButton.svelte.d.ts +19 -0
  7. package/dist/buttons/NeoButtonGroup.svelte +369 -0
  8. package/dist/buttons/NeoButtonGroup.svelte.d.ts +19 -0
  9. package/dist/buttons/index.d.ts +4 -0
  10. package/dist/buttons/index.js +2 -0
  11. package/dist/buttons/neo-button-group.model.d.ts +71 -0
  12. package/dist/buttons/neo-button-group.model.js +1 -0
  13. package/dist/buttons/neo-button.model.d.ts +110 -0
  14. package/dist/buttons/neo-button.model.js +1 -0
  15. package/dist/cards/NeoCard.svelte +413 -0
  16. package/dist/cards/NeoCard.svelte.d.ts +19 -0
  17. package/dist/cards/index.d.ts +2 -0
  18. package/dist/cards/index.js +1 -0
  19. package/dist/cards/neo-card.model.d.ts +129 -0
  20. package/dist/cards/neo-card.model.js +1 -0
  21. package/dist/containers/NeoTransitionContainer.svelte +34 -0
  22. package/dist/containers/NeoTransitionContainer.svelte.d.ts +19 -0
  23. package/dist/containers/index.d.ts +2 -0
  24. package/dist/containers/index.js +1 -0
  25. package/dist/containers/neo-transition-container.model.d.ts +25 -0
  26. package/dist/containers/neo-transition-container.model.js +1 -0
  27. package/dist/divider/NeoDivider.svelte +47 -0
  28. package/dist/divider/NeoDivider.svelte.d.ts +19 -0
  29. package/dist/divider/index.d.ts +2 -0
  30. package/dist/divider/index.js +1 -0
  31. package/dist/divider/neo-divider.model.d.ts +7 -0
  32. package/dist/divider/neo-divider.model.js +1 -0
  33. package/dist/icons/IconAccount.svelte +10 -0
  34. package/dist/icons/IconAccount.svelte.d.ts +26 -0
  35. package/dist/icons/IconAdd.svelte +10 -0
  36. package/dist/icons/IconAdd.svelte.d.ts +26 -0
  37. package/dist/icons/IconAlert.svelte +14 -0
  38. package/dist/icons/IconAlert.svelte.d.ts +26 -0
  39. package/dist/icons/IconCircleLoading.svelte +16 -0
  40. package/dist/icons/IconCircleLoading.svelte.d.ts +26 -0
  41. package/dist/icons/IconClear.svelte +10 -0
  42. package/dist/icons/IconClear.svelte.d.ts +26 -0
  43. package/dist/icons/IconClose.svelte +14 -0
  44. package/dist/icons/IconClose.svelte.d.ts +26 -0
  45. package/dist/icons/IconConfirm.svelte +10 -0
  46. package/dist/icons/IconConfirm.svelte.d.ts +26 -0
  47. package/dist/icons/IconEmpty.svelte +10 -0
  48. package/dist/icons/IconEmpty.svelte.d.ts +26 -0
  49. package/dist/icons/IconFileUpload.svelte +18 -0
  50. package/dist/icons/IconFileUpload.svelte.d.ts +26 -0
  51. package/dist/icons/IconGithub.svelte +29 -0
  52. package/dist/icons/IconGithub.svelte.d.ts +26 -0
  53. package/dist/icons/IconImage.svelte +18 -0
  54. package/dist/icons/IconImage.svelte.d.ts +26 -0
  55. package/dist/icons/IconMinus.svelte +14 -0
  56. package/dist/icons/IconMinus.svelte.d.ts +26 -0
  57. package/dist/icons/IconMoon.svelte +64 -0
  58. package/dist/icons/IconMoon.svelte.d.ts +26 -0
  59. package/dist/icons/IconSave.svelte +15 -0
  60. package/dist/icons/IconSave.svelte.d.ts +26 -0
  61. package/dist/icons/IconSaveOff.svelte +19 -0
  62. package/dist/icons/IconSaveOff.svelte.d.ts +26 -0
  63. package/dist/icons/IconSearch.svelte +14 -0
  64. package/dist/icons/IconSearch.svelte.d.ts +26 -0
  65. package/dist/icons/IconSun.svelte +54 -0
  66. package/dist/icons/IconSun.svelte.d.ts +26 -0
  67. package/dist/icons/IconSunrise.svelte +24 -0
  68. package/dist/icons/IconSunrise.svelte.d.ts +26 -0
  69. package/dist/icons/IconVideo.svelte +15 -0
  70. package/dist/icons/IconVideo.svelte.d.ts +26 -0
  71. package/dist/icons/IconWatch.svelte +21 -0
  72. package/dist/icons/IconWatch.svelte.d.ts +26 -0
  73. package/dist/icons/IconWatchOff.svelte +26 -0
  74. package/dist/icons/IconWatchOff.svelte.d.ts +26 -0
  75. package/dist/index.d.ts +8 -0
  76. package/dist/index.js +8 -0
  77. package/dist/inputs/NeoInput.svelte +750 -0
  78. package/dist/inputs/NeoInput.svelte.d.ts +27 -0
  79. package/dist/inputs/NeoPassword.svelte +31 -0
  80. package/dist/inputs/NeoPassword.svelte.d.ts +19 -0
  81. package/dist/inputs/NeoTextarea.svelte +768 -0
  82. package/dist/inputs/NeoTextarea.svelte.d.ts +27 -0
  83. package/dist/inputs/NeoValidation.svelte +106 -0
  84. package/dist/inputs/NeoValidation.svelte.d.ts +22 -0
  85. package/dist/inputs/index.d.ts +4 -0
  86. package/dist/inputs/index.js +3 -0
  87. package/dist/inputs/neo-input.model.d.ts +234 -0
  88. package/dist/inputs/neo-input.model.js +10 -0
  89. package/dist/inputs/neo-validation.model.d.ts +40 -0
  90. package/dist/inputs/neo-validation.model.js +1 -0
  91. package/dist/nav/NeoTab.svelte +170 -0
  92. package/dist/nav/NeoTab.svelte.d.ts +19 -0
  93. package/dist/nav/NeoTabPanel.svelte +75 -0
  94. package/dist/nav/NeoTabPanel.svelte.d.ts +19 -0
  95. package/dist/nav/NeoTabs.svelte +288 -0
  96. package/dist/nav/NeoTabs.svelte.d.ts +19 -0
  97. package/dist/nav/NeoTabsCard.svelte +47 -0
  98. package/dist/nav/NeoTabsCard.svelte.d.ts +19 -0
  99. package/dist/nav/index.d.ts +8 -0
  100. package/dist/nav/index.js +4 -0
  101. package/dist/nav/neo-tab-panel.model.d.ts +30 -0
  102. package/dist/nav/neo-tab-panel.model.js +1 -0
  103. package/dist/nav/neo-tab.model.d.ts +43 -0
  104. package/dist/nav/neo-tab.model.js +1 -0
  105. package/dist/nav/neo-tabs-card.model.d.ts +25 -0
  106. package/dist/nav/neo-tabs-card.model.js +5 -0
  107. package/dist/nav/neo-tabs-context.svelte.d.ts +82 -0
  108. package/dist/nav/neo-tabs-context.svelte.js +163 -0
  109. package/dist/nav/neo-tabs.model.d.ts +60 -0
  110. package/dist/nav/neo-tabs.model.js +1 -0
  111. package/dist/providers/NeoThemeProvider.svelte +28 -0
  112. package/dist/providers/NeoThemeProvider.svelte.d.ts +21 -0
  113. package/dist/providers/NeoThemeSelector.svelte +79 -0
  114. package/dist/providers/NeoThemeSelector.svelte.d.ts +19 -0
  115. package/dist/providers/index.d.ts +5 -0
  116. package/dist/providers/index.js +3 -0
  117. package/dist/providers/neo-theme-provider-context.svelte.d.ts +26 -0
  118. package/dist/providers/neo-theme-provider-context.svelte.js +78 -0
  119. package/dist/providers/neo-theme-provider.model.d.ts +35 -0
  120. package/dist/providers/neo-theme-provider.model.js +20 -0
  121. package/dist/providers/neo-theme-selector.model.d.ts +6 -0
  122. package/dist/providers/neo-theme-selector.model.js +1 -0
  123. package/dist/skeletons/NeoSkeletonContainer.svelte +48 -0
  124. package/dist/skeletons/NeoSkeletonContainer.svelte.d.ts +19 -0
  125. package/dist/skeletons/NeoSkeletonMedia.svelte +146 -0
  126. package/dist/skeletons/NeoSkeletonMedia.svelte.d.ts +19 -0
  127. package/dist/skeletons/NeoSkeletonText.svelte +170 -0
  128. package/dist/skeletons/NeoSkeletonText.svelte.d.ts +19 -0
  129. package/dist/skeletons/index.d.ts +4 -0
  130. package/dist/skeletons/index.js +2 -0
  131. package/dist/skeletons/neo-skeleton-container.model.d.ts +29 -0
  132. package/dist/skeletons/neo-skeleton-container.model.js +1 -0
  133. package/dist/skeletons/neo-skeleton-media.model.d.ts +40 -0
  134. package/dist/skeletons/neo-skeleton-media.model.js +1 -0
  135. package/dist/skeletons/neo-skeleton-text.model.d.ts +45 -0
  136. package/dist/skeletons/neo-skeleton-text.model.js +1 -0
  137. package/dist/styles/animation.scss +75 -0
  138. package/dist/styles/common/colors.scss +217 -0
  139. package/dist/styles/common/flex.scss +26 -0
  140. package/dist/styles/common/properties.css +23 -0
  141. package/dist/styles/common/shadows.scss +305 -0
  142. package/dist/styles/common/spacing.scss +27 -0
  143. package/dist/styles/common/typography.scss +13 -0
  144. package/dist/styles/common/utils.scss +8 -0
  145. package/dist/styles/common/z-index.scss +12 -0
  146. package/dist/styles/mixin.scss +225 -0
  147. package/dist/styles/reset.scss +81 -0
  148. package/dist/styles/theme.scss +22 -0
  149. package/dist/utils/action.utils.d.ts +52 -0
  150. package/dist/utils/action.utils.js +30 -0
  151. package/dist/utils/error.utils.d.ts +25 -0
  152. package/dist/utils/error.utils.js +35 -0
  153. package/dist/utils/html-element.utils.d.ts +22 -0
  154. package/dist/utils/html-element.utils.js +1 -0
  155. package/dist/utils/logger.utils.d.ts +14 -0
  156. package/dist/utils/logger.utils.js +31 -0
  157. package/dist/utils/shadow.utils.d.ts +8 -0
  158. package/dist/utils/shadow.utils.js +26 -0
  159. package/dist/utils/timeout.util.d.ts +5 -0
  160. package/dist/utils/timeout.util.js +15 -0
  161. package/dist/utils/transition.utils.d.ts +5 -0
  162. package/dist/utils/transition.utils.js +8 -0
  163. package/package.json +180 -0
@@ -0,0 +1,75 @@
1
+ <script lang="ts">
2
+ import { untrack } from 'svelte';
3
+ import { fly } from 'svelte/transition';
4
+
5
+ import type { NeoTabPanelProps } from './neo-tab-panel.model.js';
6
+
7
+ import { getTabsCardContext } from './neo-tabs-card.model.js';
8
+ import { getTabContext } from './neo-tabs-context.svelte.js';
9
+ import { emptyTransition } from '../utils/action.utils.js';
10
+
11
+ /* eslint-disable prefer-const -- necessary for binding checked */
12
+ let {
13
+ // Snippets
14
+ children,
15
+
16
+ // States
17
+ ref = $bindable(),
18
+ tabId,
19
+ empty,
20
+ tag = 'div',
21
+
22
+ // Styles
23
+ animate,
24
+
25
+ // Other props
26
+ ...rest
27
+ }: NeoTabPanelProps = $props();
28
+ /* eslint-enable prefer-const */
29
+
30
+ const context = getTabContext();
31
+ const active = $derived(context?.active === tabId);
32
+ const orientation = $derived(context?.vertical ? 'y' : 'x');
33
+
34
+ const show = $derived(empty ? !context?.active : active);
35
+
36
+ const current = $derived(context?.value?.index ?? -1);
37
+ const previous = $derived(context?.previous?.index ?? -1);
38
+ const direction = $derived(current > previous ? 1 : -1);
39
+
40
+ const ctx = getTabsCardContext();
41
+ const animated = $derived(animate || (animate !== false && ctx?.animate));
42
+
43
+ const transition = $derived(animated ? fly : emptyTransition);
44
+ const inProps = $derived(animated ? { [orientation]: `${-100 * direction}%`, duration: 600, delay: 100 } : undefined);
45
+ const outProps = $derived(animated ? { [orientation]: `${100 * direction}%`, duration: 600 } : undefined);
46
+
47
+ const paneId = $derived(tabId ? `neo-tab-panel-${String(tabId)}` : undefined);
48
+ $effect(() => {
49
+ untrack(() => {
50
+ if (!tabId || !paneId) return;
51
+ context?.registerPane(tabId, paneId);
52
+ });
53
+ return () => {
54
+ if (!tabId) return;
55
+ context?.removePane(tabId);
56
+ };
57
+ });
58
+ </script>
59
+
60
+ {#if show}
61
+ <svelte:element
62
+ this={tag}
63
+ role="tabpanel"
64
+ id={paneId}
65
+ aria-labelledby={tabId ? `neo-tab-${String(tabId)}` : undefined}
66
+ data-tab-id={tabId ?? (empty ? 'empty' : undefined)}
67
+ bind:this={ref}
68
+ class:neo-tab-panel={true}
69
+ {...rest}
70
+ in:transition={inProps}
71
+ out:transition={outProps}
72
+ >
73
+ {@render children?.(context?.state)}
74
+ </svelte:element>
75
+ {/if}
@@ -0,0 +1,19 @@
1
+ import type { NeoTabPanelProps } from './neo-tab-panel.model.js';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const NeoTabPanel: $$__sveltets_2_IsomorphicComponent<NeoTabPanelProps, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, "ref">;
18
+ type NeoTabPanel = InstanceType<typeof NeoTabPanel>;
19
+ export default NeoTabPanel;
@@ -0,0 +1,288 @@
1
+ <script lang="ts">
2
+ import { height, width } from '@dvcol/svelte-utils/transition';
3
+
4
+ import { untrack } from 'svelte';
5
+
6
+ import type { NeoTabContextPositions, NeoTabsContext } from './neo-tabs-context.svelte.js';
7
+
8
+ import type { NeoTabsProps, OnChange } from './neo-tabs.model.js';
9
+
10
+ import NeoButton from '../buttons/NeoButton.svelte';
11
+ import NeoButtonGroup from '../buttons/NeoButtonGroup.svelte';
12
+ import IconAdd from '../icons/IconAdd.svelte';
13
+ import { setTabContext } from './neo-tabs-context.svelte.js';
14
+
15
+ import { toAction, toActionProps, toTransition, toTransitionProps } from '../utils/action.utils.js';
16
+
17
+ /* eslint-disable prefer-const -- necessary for binding checked */
18
+ let {
19
+ // Snippets
20
+ children,
21
+ panes,
22
+
23
+ // States
24
+ ref = $bindable(),
25
+ active = $bindable(),
26
+ disabled,
27
+
28
+ // Styles
29
+ before,
30
+ toggle,
31
+ close,
32
+ add,
33
+ slide,
34
+ line,
35
+
36
+ // Events
37
+ onchange,
38
+ onclose,
39
+ onadd,
40
+
41
+ // Other props
42
+ containerTag = 'div',
43
+ containerProps,
44
+ ...rest
45
+ }: NeoTabsProps = $props();
46
+ /* eslint-enable prefer-const */
47
+
48
+ // reflect context active to component
49
+ const onChange: OnChange = (_tabId, _new, _old) => {
50
+ active = _tabId;
51
+ onchange?.(_tabId, _new, _old);
52
+ };
53
+
54
+ const context = setTabContext({ onChange, onClose: onclose });
55
+ const transition = $derived(rest.vertical ? height : width);
56
+
57
+ let translate = $state(transform(context.position));
58
+ // Function to compute the transform
59
+ function transform({ oldTab, newTab }: NeoTabContextPositions) {
60
+ if (!newTab) return;
61
+ if (!oldTab) return;
62
+
63
+ // Calculate the difference in positions
64
+ const offsetX = oldTab.left - newTab.left;
65
+ const offsetY = oldTab.top - newTab.top;
66
+
67
+ // Apply the transform to position absDiv over targetDiv
68
+ return `--neo-tabs-transform: translate(${offsetX}px, ${offsetY}px); --neo-tab-old-width: ${oldTab.width}px; --neo-tab-old-height: ${oldTab.height}px;`;
69
+ }
70
+
71
+ $effect.pre(() => {
72
+ if (!slide) return;
73
+ translate = transform(context.position);
74
+ });
75
+
76
+ const style = $derived([containerProps?.style, translate].filter(Boolean).join('; '));
77
+
78
+ // reflect component active to context
79
+ $effect(() => {
80
+ if (active === context.active) return;
81
+ untrack(() => context.onChange(active));
82
+ });
83
+
84
+ $effect.pre(() => {
85
+ context.onOption({
86
+ // States
87
+ disabled,
88
+
89
+ // Styles
90
+ slide,
91
+ toggle,
92
+ add,
93
+ close,
94
+ glass: rest.glass,
95
+ inset: rest.inset,
96
+ shallow: rest.shallow,
97
+ vertical: rest.vertical,
98
+ flat: rest.flat,
99
+ text: rest.text,
100
+ });
101
+ });
102
+
103
+ const inFn = $derived(toTransition(containerProps?.in ?? containerProps?.transition));
104
+ const inProps = $derived(toTransitionProps(containerProps?.in ?? containerProps?.transition));
105
+ const outFn = $derived(toTransition(containerProps?.out ?? containerProps?.transition));
106
+ const outProps = $derived(toTransitionProps(containerProps?.out ?? containerProps?.transition));
107
+
108
+ const useFn = $derived(toAction(containerProps?.use));
109
+ const useProps = $derived(toActionProps(containerProps?.use));
110
+ </script>
111
+
112
+ {#snippet icon()}
113
+ <IconAdd class="neo-tabs-add" />
114
+ {/snippet}
115
+
116
+ {#snippet tabs(ctx: NeoTabsContext = context.state)}
117
+ <svelte:element
118
+ this={containerTag}
119
+ bind:this={ref}
120
+ class:neo-tabs={true}
121
+ class:add
122
+ class:line
123
+ class:slide
124
+ class:translate
125
+ class:flat={rest.flat}
126
+ class:text={rest.text}
127
+ class:vertical={rest.vertical}
128
+ class:rounded={rest.rounded}
129
+ class:shallow={rest.shallow}
130
+ {...containerProps}
131
+ use:useFn={useProps}
132
+ out:outFn={outProps}
133
+ in:inFn={inProps}
134
+ {style}
135
+ >
136
+ <NeoButtonGroup role="tablist" {...rest}>
137
+ {@render children?.(ctx)}
138
+ {#if add}
139
+ <div transition:transition={{ duration: 200, css: `overflow: hidden; white-space: nowrap` }}>
140
+ <NeoButton onclick={onadd} {icon} />
141
+ </div>
142
+ {/if}
143
+ </NeoButtonGroup>
144
+ </svelte:element>
145
+ {/snippet}
146
+
147
+ {#if before}
148
+ {@render panes?.(context.state)}
149
+ {/if}
150
+
151
+ {@render tabs()}
152
+
153
+ {#if !before}
154
+ {@render panes?.(context.state)}
155
+ {/if}
156
+
157
+ <style>.neo-tabs {
158
+ display: inline-flex;
159
+ flex: 0 1 auto;
160
+ flex-flow: row wrap;
161
+ }
162
+ .neo-tabs :global(.neo-tabs-add) {
163
+ min-width: 1rem;
164
+ }
165
+ .neo-tabs.vertical :global(.neo-tab) {
166
+ position: relative;
167
+ width: 100%;
168
+ min-width: max-content;
169
+ }
170
+ .neo-tabs.vertical :global(.neo-tab .neo-button) {
171
+ justify-content: flex-start;
172
+ }
173
+ .neo-tabs.vertical :global(.neo-tab-close .icon-close) {
174
+ position: absolute;
175
+ top: calc(50% - 0.5rem);
176
+ }
177
+ .neo-tabs.vertical :global(.neo-tab-close:not(.reverse) .icon-close) {
178
+ right: 0.75rem;
179
+ }
180
+ .neo-tabs.vertical :global(.neo-tab-close.reverse .icon-close) {
181
+ left: 0.75rem;
182
+ }
183
+ .neo-tabs.vertical.add :global(.neo-button-group) {
184
+ padding-bottom: 0.5rem;
185
+ }
186
+ .neo-tabs.vertical.line :global(.neo-tab::before) {
187
+ --neo-tab-width: 2px;
188
+ --neo-tab-old-width: 2px;
189
+ --neo-tab-old-max-height: calc(var(--neo-tab-old-height, 100%) - 1rem);
190
+ --neo-tab-max-height: calc(var(--neo-tab-height, 100%) - 1rem);
191
+ top: 0;
192
+ width: 2px;
193
+ height: 0;
194
+ max-height: var(--neo-tab-max-height);
195
+ margin-left: 0.3rem;
196
+ transition: box-shadow 0.3s ease, height 0.3s var(--neo-transition-bezier);
197
+ margin-block: 0.5rem;
198
+ }
199
+ .neo-tabs.vertical.line :global(.neo-tab.active::before) {
200
+ height: var(--neo-tab-height, 100%);
201
+ }
202
+ .neo-tabs.add:not(.vertical) :global(.neo-button-group) {
203
+ padding-right: 0.5rem;
204
+ }
205
+ .neo-tabs.slide {
206
+ --neo-tab-width: 100%;
207
+ --neo-tab-height: 100%;
208
+ }
209
+ .neo-tabs.slide :global(.neo-tab .neo-button) {
210
+ box-shadow: var(--neo-box-shadow-flat) !important;
211
+ }
212
+ .neo-tabs.slide :global(.neo-tab) {
213
+ position: relative;
214
+ }
215
+ .neo-tabs.slide :global(.neo-tab::before) {
216
+ position: absolute;
217
+ top: 0;
218
+ left: 0;
219
+ z-index: var(--neo-z-index-in-front, 1);
220
+ width: var(--neo-tab-width, 100%);
221
+ height: var(--neo-tab-height, 100%);
222
+ border: var(--neo-border-width, 1px) var(--neo-tab-border-color, transparent) solid;
223
+ border-radius: var(--neo-tab-border-radius, var(--neo-border-radius));
224
+ box-shadow: var(--neo-box-shadow-flat);
225
+ backface-visibility: hidden;
226
+ transition: box-shadow 0.3s ease;
227
+ content: "";
228
+ pointer-events: none;
229
+ }
230
+ .neo-tabs.slide.line :global(.neo-tab.active::before) {
231
+ top: unset;
232
+ bottom: 0;
233
+ background-color: var(--neo-color-primary, var(--neo-text-color));
234
+ box-shadow: var(--neo-box-shadow-flat);
235
+ }
236
+ .neo-tabs.slide.line:not(.vertical) :global(.neo-tab::before) {
237
+ --neo-tab-height: 2px;
238
+ --neo-tab-old-height: 2px;
239
+ --neo-tab-old-max-width: calc(var(--neo-tab-old-width, 100%) - 1.5rem);
240
+ --neo-tab-max-width: calc(var(--neo-tab-width, 100%) - 1.5rem);
241
+ width: 0;
242
+ max-width: var(--neo-tab-max-width);
243
+ height: 2px;
244
+ margin-bottom: 0.125rem;
245
+ transition: box-shadow 0.3s ease, width 0.3s var(--neo-transition-bezier);
246
+ margin-inline: 0.75rem;
247
+ }
248
+ .neo-tabs.slide.line:not(.vertical) :global(.neo-tab.active::before) {
249
+ width: var(--neo-tab-width, 100%);
250
+ }
251
+ .neo-tabs.slide :global(.neo-tab.active::before) {
252
+ box-shadow: var(--neo-box-shadow-inset-3);
253
+ }
254
+ .neo-tabs.slide.translate :global(.neo-tab.active::before) {
255
+ animation: slide 0.6s var(--neo-transition-bezier) forwards;
256
+ }
257
+ @keyframes slide {
258
+ 0% {
259
+ width: var(--neo-tab-old-width, var(--neo-tab-width, 100%));
260
+ max-width: var(--neo-tab-old-max-width);
261
+ height: var(--neo-tab-old-height, var(--neo-tab-height, 100%));
262
+ max-height: var(--neo-tab-old-max-height);
263
+ box-shadow: var(--neo-box-shadow-inset-3);
264
+ transform: var(--neo-tabs-transform);
265
+ }
266
+ 100% {
267
+ width: var(--neo-tab-width, 100%);
268
+ max-width: var(--neo-tab-max-width);
269
+ height: var(--neo-tab-height, 100%);
270
+ max-height: var(--neo-tab-max-height);
271
+ box-shadow: var(--neo-box-shadow-inset-3);
272
+ transform: translate(0, 0);
273
+ }
274
+ }
275
+ @keyframes fade {
276
+ 0% {
277
+ box-shadow: var(--neo-box-shadow-flat);
278
+ }
279
+ 100% {
280
+ box-shadow: var(--neo-box-shadow-inset-3);
281
+ }
282
+ }
283
+ .neo-tabs.slide.shallow {
284
+ --neo-box-shadow-inset-3: var(--neo-box-shadow-inset-2);
285
+ }
286
+ .neo-tabs.slide.rounded :global(.neo-button-group .neo-tab::before) {
287
+ border-radius: var(--neo-tab-border-radius, var(--neo-border-radius-lg));
288
+ }</style>
@@ -0,0 +1,19 @@
1
+ import type { NeoTabsProps } from './neo-tabs.model.js';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const NeoTabs: $$__sveltets_2_IsomorphicComponent<NeoTabsProps, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, "ref" | "active">;
18
+ type NeoTabs = InstanceType<typeof NeoTabs>;
19
+ export default NeoTabs;
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import NeoCard from '../cards/NeoCard.svelte';
3
+ import NeoTransitionContainer from '../containers/NeoTransitionContainer.svelte';
4
+ import { type NeoTabsCardProps, setTabsCardContext } from './neo-tabs-card.model.js';
5
+ import { getTabContext } from './neo-tabs-context.svelte.js';
6
+
7
+ /* eslint-disable prefer-const -- necessary for binding checked */
8
+ let {
9
+ // Snippets
10
+ children,
11
+
12
+ // States
13
+ ref = $bindable(),
14
+
15
+ // Styles
16
+ animate = true,
17
+
18
+ // Other props
19
+ containerProps,
20
+ ...rest
21
+ }: NeoTabsCardProps = $props();
22
+ /* eslint-enable prefer-const */
23
+
24
+ const context = getTabContext();
25
+ const glass = $derived(context?.glass);
26
+ const borderless = $derived(context?.text);
27
+
28
+ const elevation = $derived.by(() => {
29
+ if (context?.flat) return 0;
30
+ if (context?.inset) return context?.shallow ? -1 : -2;
31
+ return context?.shallow ? 1 : 2;
32
+ });
33
+
34
+ $effect.pre(() => {
35
+ setTabsCardContext({ animate });
36
+ });
37
+ </script>
38
+
39
+ <NeoCard bind:ref {elevation} {borderless} {glass} {...rest}>
40
+ {#if animate}
41
+ <NeoTransitionContainer {...containerProps}>
42
+ {@render children?.(context?.state)}
43
+ </NeoTransitionContainer>
44
+ {:else}
45
+ {@render children?.(context?.state)}
46
+ {/if}
47
+ </NeoCard>
@@ -0,0 +1,19 @@
1
+ import { type NeoTabsCardProps } from './neo-tabs-card.model.js';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const NeoTabsCard: $$__sveltets_2_IsomorphicComponent<NeoTabsCardProps, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, "ref">;
18
+ type NeoTabsCard = InstanceType<typeof NeoTabsCard>;
19
+ export default NeoTabsCard;
@@ -0,0 +1,8 @@
1
+ export { default as NeoTab } from './NeoTab.svelte';
2
+ export { default as NeoTabs } from './NeoTabs.svelte';
3
+ export { default as NeoTabPanel } from './NeoTabPanel.svelte';
4
+ export { default as NeoTabsCard } from './NeoTabsCard.svelte';
5
+ export type { NeoTabProps, TabId } from './neo-tab.model.js';
6
+ export type { NeoTabsProps, NeoTabsContainerProps, NeoTabContextValue, OnClose, OnChange } from './neo-tabs.model.js';
7
+ export type { NeoTabPanelProps } from './neo-tab-panel.model.js';
8
+ export type { NeoTabsCardProps, NeoTabsCardContext } from './neo-tabs-card.model.js';
@@ -0,0 +1,4 @@
1
+ export { default as NeoTab } from './NeoTab.svelte';
2
+ export { default as NeoTabs } from './NeoTabs.svelte';
3
+ export { default as NeoTabPanel } from './NeoTabPanel.svelte';
4
+ export { default as NeoTabsCard } from './NeoTabsCard.svelte';
@@ -0,0 +1,30 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { TabId } from './neo-tab.model.js';
3
+ import type { NeoTabsContext } from './neo-tabs-context.svelte.js';
4
+ import type { HTMLNeoBaseElement, HTMLRefProps } from '../utils/html-element.utils.js';
5
+ export type NeoTabPanelProps<T = unknown> = {
6
+ /**
7
+ * Snippet to display as the tab content.
8
+ */
9
+ children?: Snippet<[NeoTabsContext<T> | undefined]>;
10
+ /**
11
+ * The tab id to associate with this pane.
12
+ */
13
+ tabId?: TabId;
14
+ /**
15
+ * If `true`, the pane will appear when no other tabs are active.
16
+ */
17
+ empty?: boolean;
18
+ /**
19
+ * The HTML tag to use for the container id `animate` is true.
20
+ * @default 'div'
21
+ * @see animate
22
+ */
23
+ tag?: keyof HTMLElementTagNameMap;
24
+ /**
25
+ * If `true`, pane transition will be animated.
26
+ * If `false`, the pane will check if any neo-tabs-card parent is animating.
27
+ * @default false
28
+ */
29
+ animate?: boolean;
30
+ } & HTMLNeoBaseElement & HTMLRefProps;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { NeoButtonProps } from '../buttons/neo-button.model.js';
3
+ import type { OnChange } from './neo-tabs.model.js';
4
+ import type { HTMLUseProps } from '../utils/action.utils.js';
5
+ import type { HTMLNeoBaseElement, HTMLRefProps } from '../utils/html-element.utils.js';
6
+ export type TabId = string | number | symbol;
7
+ export type NeoTabProps<T = unknown> = {
8
+ /**
9
+ * Snippet to display as the tab content.
10
+ */
11
+ children?: Snippet<[{
12
+ active: boolean;
13
+ tabId: TabId;
14
+ value?: unknown;
15
+ }]>;
16
+ /**
17
+ * The HTML tag to use for the tab.
18
+ * @default 'div'
19
+ */
20
+ tag?: keyof HTMLElementTagNameMap;
21
+ /**
22
+ * A unique identifier for the tab.
23
+ * If none is provided, the tab will be assigned a random id.
24
+ */
25
+ tabId?: TabId;
26
+ /**
27
+ * Optional value to associate with the tab.
28
+ */
29
+ value?: T;
30
+ /**
31
+ * If true, the tab will display a close button that broadcasts the `onclose` event.
32
+ * Note: The event will also be emitted to a parent `NeoTabs` if present.
33
+ */
34
+ close?: boolean;
35
+ /**
36
+ * Event handler that fires wwhen the close button is clicked.
37
+ */
38
+ onclose?: OnChange<T>;
39
+ /**
40
+ * Optional props to pass to the tab container.
41
+ */
42
+ tabProps?: HTMLNeoBaseElement & HTMLUseProps;
43
+ } & Omit<NeoButtonProps, 'value' | 'children' | 'ref'> & HTMLRefProps;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { NeoCardProps } from '../cards/neo-card.model.js';
3
+ import type { NeoTransitionContainerProps } from '../containers/neo-transition-container.model.js';
4
+ import { type NeoTabsContext } from './neo-tabs-context.svelte.js';
5
+ export type NeoTabsCardContext = {
6
+ /**
7
+ * If `true`, pane transition will be animated.
8
+ * @default true
9
+ */
10
+ animate?: boolean;
11
+ };
12
+ export type NeoTabsCardProps<T = unknown> = {
13
+ /**
14
+ * Snippet to display as the card content.
15
+ */
16
+ children?: Snippet<[NeoTabsContext<T> | undefined]>;
17
+ /**
18
+ * Optional props to pass to the tab container if `animate` is `true`.
19
+ * @see animate
20
+ */
21
+ containerProps?: NeoTransitionContainerProps;
22
+ } & NeoTabsCardContext & Omit<NeoCardProps, 'children'>;
23
+ export declare const NeoTabsCardContextSymbol: unique symbol;
24
+ export declare const setTabsCardContext: (context: NeoTabsCardContext) => NeoTabsCardContext;
25
+ export declare const getTabsCardContext: () => NeoTabsCardContext | undefined;
@@ -0,0 +1,5 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ import {} from './neo-tabs-context.svelte.js';
3
+ export const NeoTabsCardContextSymbol = Symbol('NeoTabsCardContext');
4
+ export const setTabsCardContext = (context) => setContext(NeoTabsCardContextSymbol, context);
5
+ export const getTabsCardContext = () => getContext(NeoTabsCardContextSymbol);
@@ -0,0 +1,82 @@
1
+ import type { NeoButtonGroupProps } from '../buttons/neo-button-group.model.js';
2
+ import type { TabId } from './neo-tab.model.js';
3
+ import type { NeoTabContextValue, OnChange, OnClose } from './neo-tabs.model.js';
4
+ export type NeoTabContextPosition = {
5
+ id: TabId;
6
+ top: number;
7
+ left: number;
8
+ width: number;
9
+ height: number;
10
+ };
11
+ export type NeoTabContextPositions = {
12
+ oldTab?: NeoTabContextPosition;
13
+ newTab?: NeoTabContextPosition;
14
+ };
15
+ type NeoTabContextOptions = {
16
+ /**
17
+ * Disables all tabs.
18
+ */
19
+ disabled?: boolean;
20
+ /**
21
+ * Whether to animate the tab transition.
22
+ */
23
+ slide?: boolean;
24
+ /**
25
+ * Clicking the active tab will unselect it.
26
+ */
27
+ toggle?: boolean;
28
+ /**
29
+ * Add a button to add new tabs.
30
+ */
31
+ add?: boolean;
32
+ /**
33
+ * Add a close button to each tab.
34
+ */
35
+ close?: boolean;
36
+ } & Pick<NeoButtonGroupProps, 'vertical' | 'shallow' | 'inset' | 'glass' | 'flat' | 'text'>;
37
+ export type NeoTabsContext<T = unknown> = NeoTabContextOptions & {
38
+ /**
39
+ * The active tab ID.
40
+ */
41
+ active?: TabId;
42
+ /**
43
+ * The active tab value.
44
+ */
45
+ value?: NeoTabContextValue<T>;
46
+ };
47
+ type NeoTabContextCallbacks<T = unknown> = {
48
+ onChange?: OnChange<T>;
49
+ onClose?: OnClose<T>;
50
+ };
51
+ export declare class NeoTabContext<T = unknown> {
52
+ #private;
53
+ get active(): TabId | undefined;
54
+ get value(): NeoTabContextValue<T> | undefined;
55
+ get previous(): NeoTabContextValue<T> | undefined;
56
+ get disabled(): boolean | undefined;
57
+ get slide(): boolean | undefined;
58
+ get toggle(): boolean | undefined;
59
+ get close(): boolean | undefined;
60
+ get shallow(): boolean | undefined;
61
+ get inset(): boolean | undefined;
62
+ get glass(): boolean | undefined;
63
+ get vertical(): boolean | undefined;
64
+ get position(): NeoTabContextPositions;
65
+ get text(): boolean | undefined;
66
+ get flat(): boolean | undefined;
67
+ get state(): NeoTabsContext;
68
+ constructor({ onChange, onClose }?: NeoTabContextCallbacks<T>);
69
+ getValue(tabId?: TabId): NeoTabContextValue<T> | undefined;
70
+ getPane(tabId?: TabId): TabId | undefined;
71
+ onOption(options: NeoTabContextOptions): void;
72
+ onPosition(_ref?: HTMLElement | undefined): NeoTabContextPositions;
73
+ onChange(tabId?: TabId, emit?: boolean): void;
74
+ onClose(tabId?: TabId): void;
75
+ register(tabId: TabId, value: Omit<NeoTabContextValue<T>, 'index'>): any;
76
+ remove(tabId: TabId): void;
77
+ registerPane(tabId: TabId, panelId: TabId): any;
78
+ removePane(tabId: TabId): void;
79
+ }
80
+ export declare const getTabContext: <T = unknown>() => NeoTabContext<T> | undefined;
81
+ export declare const setTabContext: <T = unknown>(callback?: NeoTabContextCallbacks<T>) => NeoTabContext<T>;
82
+ export {};