@finggujadhav/svelte 0.9.0

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/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@finggujadhav/svelte",
3
+ "version": "0.9.0",
4
+ "description": "Svelte adapter for FingguFlux UI library",
5
+ "main": "dist/index.js",
6
+ "module": "src/index.ts",
7
+ "types": "src/index.ts",
8
+ "scripts": {
9
+ "build": "echo 'Svelte components do not require pre-build for this release'"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "exports": {
16
+ ".": {
17
+ "types": "./src/index.ts",
18
+ "import": "./src/index.ts"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@finggujadhav/core": "0.9.0",
23
+ "@finggujadhav/js-helper": "0.9.0"
24
+ },
25
+ "peerDependencies": {
26
+ "svelte": ">=3.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "svelte": "^3.0.0",
30
+ "typescript": "^5.0.0"
31
+ }
32
+ }
@@ -0,0 +1,53 @@
1
+ <script lang="ts" context="module">
2
+ const VARIANTS = {
3
+ primary: 'ff-btn-primary',
4
+ secondary: 'ff-btn-secondary',
5
+ ghost: 'ff-btn-ghost',
6
+ outline: 'ff-btn-outline'
7
+ } as const;
8
+
9
+ const SIZES = {
10
+ sm: 'ff-btn-sm',
11
+ md: 'ff-btn-md',
12
+ lg: 'ff-btn-lg'
13
+ } as const;
14
+
15
+ const MOTIONS = {
16
+ fade: 'ff-fade-in',
17
+ 'slide-up': 'ff-slide-up',
18
+ 'scale-in': 'ff-scale-in',
19
+ lift: 'ff-hover-lift'
20
+ } as const;
21
+
22
+ export const __ffClasses_Button = [
23
+ 'ff-btn',
24
+ ...Object.values(VARIANTS),
25
+ ...Object.values(SIZES),
26
+ ...Object.values(MOTIONS),
27
+ 'ff-card-glass'
28
+ ];
29
+ </script>
30
+
31
+ <script lang="ts">
32
+ import { useFinggu } from './context';
33
+
34
+ export let variant: keyof typeof VARIANTS = 'primary';
35
+ export let size: keyof typeof SIZES = 'md';
36
+ export let motion: keyof typeof MOTIONS | undefined = undefined;
37
+ export let glass: boolean = false;
38
+
39
+ const finggu = useFinggu();
40
+
41
+ $: ffClasses = $finggu.resolveAll([
42
+ 'ff-btn',
43
+ VARIANTS[variant],
44
+ SIZES[size],
45
+ glass && 'ff-card-glass',
46
+ motion && MOTIONS[motion],
47
+ $$props.class
48
+ ]);
49
+ </script>
50
+
51
+ <button class={ffClasses} {...$$restProps}>
52
+ <slot />
53
+ </button>
@@ -0,0 +1,41 @@
1
+ <script lang="ts" context="module">
2
+ const VARIANTS = {
3
+ outline: 'ff-card-outline',
4
+ glass: 'ff-card-glass'
5
+ } as const;
6
+
7
+ const PADDINGS = {
8
+ none: 'ff-p-0',
9
+ sm: 'ff-p-2',
10
+ md: 'ff-p-4',
11
+ lg: 'ff-p-8'
12
+ } as const;
13
+
14
+ export const __ffClasses_Card = [
15
+ 'ff-card',
16
+ 'ff-card-header',
17
+ 'ff-card-body',
18
+ ...Object.values(VARIANTS),
19
+ ...Object.values(PADDINGS)
20
+ ];
21
+ </script>
22
+
23
+ <script lang="ts">
24
+ import { useFinggu } from './context';
25
+
26
+ export let variant: keyof typeof VARIANTS | undefined = undefined;
27
+ export let padding: keyof typeof PADDINGS = 'md';
28
+
29
+ const finggu = useFinggu();
30
+
31
+ $: ffClasses = $finggu.resolveAll([
32
+ 'ff-card',
33
+ variant && VARIANTS[variant],
34
+ PADDINGS[padding],
35
+ $$props.class
36
+ ]);
37
+ </script>
38
+
39
+ <div class={ffClasses} {...$$restProps}>
40
+ <slot />
41
+ </div>
@@ -0,0 +1,69 @@
1
+ <script lang="ts" context="module">
2
+ export const __ffClasses_Dropdown = [
3
+ 'ff-dropdown',
4
+ 'ff-dropdown-trigger',
5
+ 'ff-dropdown-menu',
6
+ 'ff-dropdown-menu-right',
7
+ 'ff-dropdown-item'
8
+ ];
9
+ </script>
10
+
11
+ <script lang="ts">
12
+ import { onMount, onDestroy } from 'svelte';
13
+ import { useFinggu } from './context';
14
+
15
+ export let align: 'left' | 'right' = 'left';
16
+
17
+ const finggu = useFinggu();
18
+ let isOpen = false;
19
+ let container: HTMLElement;
20
+
21
+ function toggle() { isOpen = !isOpen; }
22
+ function close() { isOpen = false; }
23
+
24
+ function handleClickOutside(event: MouseEvent) {
25
+ if (container && !container.contains(event.target as Node)) {
26
+ close();
27
+ }
28
+ }
29
+
30
+ onMount(() => {
31
+ if (typeof document !== 'undefined') {
32
+ document.addEventListener('mousedown', handleClickOutside);
33
+ }
34
+ });
35
+
36
+ onDestroy(() => {
37
+ if (typeof document !== 'undefined') {
38
+ document.removeEventListener('mousedown', handleClickOutside);
39
+ }
40
+ });
41
+
42
+ $: ffContainerClasses = $finggu.resolveAll(['ff-dropdown']);
43
+ $: ffTriggerClasses = $finggu.resolveAll(['ff-dropdown-trigger']);
44
+ $: ffMenuClasses = $finggu.resolveAll([
45
+ 'ff-dropdown-menu',
46
+ align === 'right' && 'ff-dropdown-menu-right'
47
+ ]);
48
+ </script>
49
+
50
+ <div class={ffContainerClasses} bind:this={container}>
51
+ <button
52
+ type="button"
53
+ class={ffTriggerClasses}
54
+ on:click={toggle}
55
+ aria-haspopup="true"
56
+ aria-expanded={isOpen}
57
+ >
58
+ <slot name="trigger" />
59
+ </button>
60
+
61
+ <div
62
+ class={ffMenuClasses}
63
+ data-ff-state={isOpen ? 'open' : 'closed'}
64
+ role="menu"
65
+ aria-hidden={!isOpen}
66
+ >
67
+ <slot />
68
+ </div>
69
+ </div>
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ import { useFinggu } from './context';
3
+ const finggu = useFinggu();
4
+ $: ffClasses = $finggu.resolveAll(['ff-dropdown-item', $$props.class]);
5
+ </script>
6
+
7
+ <div class={ffClasses} {...$$restProps}>
8
+ <slot />
9
+ </div>
@@ -0,0 +1,22 @@
1
+ <script lang="ts" context="module">
2
+ export const __ffClasses_Input = [
3
+ 'ff-input',
4
+ 'ff-input-error'
5
+ ];
6
+ </script>
7
+
8
+ <script lang="ts">
9
+ import { useFinggu } from './context';
10
+
11
+ export let error: boolean = false;
12
+
13
+ const finggu = useFinggu();
14
+
15
+ $: ffClasses = $finggu.resolveAll([
16
+ 'ff-input',
17
+ error && 'ff-input-error',
18
+ $$props.class
19
+ ]);
20
+ </script>
21
+
22
+ <input class={ffClasses} {...$$restProps} />
@@ -0,0 +1,59 @@
1
+ <script lang="ts" context="module">
2
+ export const __ffClasses_Modal = [
3
+ 'ff-modal',
4
+ 'ff-modal-open',
5
+ 'ff-modal-closed',
6
+ 'ff-modal-overlay',
7
+ 'ff-modal-content'
8
+ ];
9
+ </script>
10
+
11
+ <script lang="ts">
12
+ import { onMount, createEventDispatcher } from 'svelte';
13
+ import { useFinggu } from './context';
14
+
15
+ export let isOpen: boolean = false;
16
+
17
+ const dispatch = createEventDispatcher();
18
+ const finggu = useFinggu();
19
+
20
+ let mounted = false;
21
+ let animating = false;
22
+
23
+ onMount(() => {
24
+ mounted = true;
25
+ });
26
+
27
+ $: if (isOpen) {
28
+ if (typeof document !== 'undefined') {
29
+ document.body.style.overflow = 'hidden';
30
+ animating = true;
31
+ }
32
+ } else {
33
+ if (typeof document !== 'undefined') {
34
+ setTimeout(() => {
35
+ animating = false;
36
+ document.body.style.overflow = '';
37
+ }, 300); // Exit animation duration
38
+ }
39
+ }
40
+
41
+ $: ffContainerClasses = $finggu.resolveAll([
42
+ 'ff-modal',
43
+ isOpen ? 'ff-modal-open' : 'ff-modal-closed'
44
+ ]);
45
+
46
+ $: ffContentClasses = $finggu.resolveAll([
47
+ 'ff-modal-content',
48
+ $$props.class
49
+ ]);
50
+ </script>
51
+
52
+ {#if mounted && (isOpen || animating)}
53
+ <div class={ffContainerClasses} aria-hidden={!isOpen}>
54
+ <div class="ff-modal-overlay" on:click={() => dispatch('close')} />
55
+ <div class={ffContentClasses}>
56
+ <slot />
57
+ </div>
58
+ </div>
59
+ {/if}
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { getContext } from 'svelte';
3
+ import { TABS_KEY, type TabsContext } from './tabs-shared';
4
+
5
+ export let value: string;
6
+ const context = getContext<TabsContext>(TABS_KEY);
7
+
8
+ $: active = $context?.activeTab ? $context.activeTab : null;
9
+ $: visible = $active === value;
10
+ </script>
11
+
12
+ {#if visible}
13
+ <div class="ff-tab-content" {...$$restProps}>
14
+ <slot />
15
+ </div>
16
+ {/if}
@@ -0,0 +1,3 @@
1
+ <div class="ff-tab-list" role="tablist" {...$$restProps}>
2
+ <slot />
3
+ </div>
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import { getContext } from 'svelte';
3
+ import { TABS_KEY, type TabsContext } from './tabs-shared';
4
+ import { useFinggu } from './context';
5
+
6
+ export let value: string;
7
+
8
+ const finggu = useFinggu();
9
+ const context = getContext<TabsContext>(TABS_KEY);
10
+
11
+ $: isActive = $context?.activeTab ? $context.activeTab : null;
12
+ $: active = $isActive === value;
13
+
14
+ $: ffClasses = $finggu.resolveAll([
15
+ 'ff-tab',
16
+ active && 'ff-tab-active',
17
+ $$props.class
18
+ ]);
19
+
20
+ function select() {
21
+ context?.activeTab.set(value);
22
+ }
23
+ </script>
24
+
25
+ <button
26
+ role="tab"
27
+ aria-selected={active}
28
+ class={ffClasses}
29
+ on:click={select}
30
+ {...$$restProps}
31
+ >
32
+ <slot />
33
+ </button>
@@ -0,0 +1,13 @@
1
+ <script lang="ts">
2
+ import { setContext } from 'svelte';
3
+ import { writable } from 'svelte/store';
4
+ import { TABS_KEY } from './tabs-shared';
5
+
6
+ export let defaultValue: string;
7
+ const activeTab = writable(defaultValue);
8
+ setContext(TABS_KEY, { activeTab });
9
+ </script>
10
+
11
+ <div class="ff-tabs" {...$$restProps}>
12
+ <slot />
13
+ </div>
package/src/context.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { setContext, getContext } from 'svelte';
2
+ import { writable, derived, type Readable } from 'svelte/store';
3
+ import { setTheme, FingguTheme } from '@finggujadhav/js-helper';
4
+
5
+ export interface FingguMapping {
6
+ _version?: string;
7
+ [key: string]: string | undefined;
8
+ }
9
+
10
+ export interface FingguContextValue {
11
+ mapping: FingguMapping | null;
12
+ mode: 'dev' | 'opt' | 'ext';
13
+ version?: string;
14
+ theme?: FingguTheme;
15
+ }
16
+
17
+ const FINGGU_KEY = Symbol('FingguFlux');
18
+
19
+ /**
20
+ * Initialize FingguFlux context in a layout or root component.
21
+ */
22
+ export function setFingguContext(initial: FingguContextValue & { theme?: FingguTheme }) {
23
+ const theme = initial.theme || 'system';
24
+ const store = writable<FingguContextValue & { theme: FingguTheme }>({
25
+ ...initial,
26
+ theme
27
+ });
28
+
29
+ // Version Guard
30
+ if (initial.mapping && initial.version && initial.mapping._version && initial.mapping._version !== initial.version) {
31
+ console.warn(`[FingguFlux] Version Mismatch: mapping.json (${initial.mapping._version}) does not match expected CSS version (${initial.version})`);
32
+ }
33
+
34
+ // Apply theme
35
+ if (typeof document !== 'undefined') {
36
+ setTheme(theme);
37
+ }
38
+
39
+ setContext(FINGGU_KEY, store);
40
+ return store;
41
+ }
42
+
43
+ /**
44
+ * useFinggu for class resolution within Svelte components.
45
+ */
46
+ export function useFinggu() {
47
+ const store = getContext<Readable<FingguContextValue>>(FINGGU_KEY);
48
+
49
+ // Fallback if context is missing (SSR safety or misconfiguration)
50
+ const fallback: FingguContextValue = { mapping: null, mode: 'dev' };
51
+
52
+ return derived(store || writable(fallback), ($finggu) => {
53
+ const resolve = (className: string): string => {
54
+ if ($finggu.mode === 'dev' || !$finggu.mapping) return className;
55
+
56
+ const mapped = $finggu.mapping[className];
57
+ if ($finggu.mode === 'ext' && !mapped && className.startsWith('ff-')) {
58
+ const errorMsg = `[FingguFlux] Critical: Class '${className}' not found in mapping.json in Extreme mode. This will cause broken styles in production.`;
59
+
60
+ // SvelteKit dev check
61
+ // @ts-ignore
62
+ const isDev = typeof process !== 'undefined' ? process.env.NODE_ENV === 'development' : (import.meta as any).env?.DEV;
63
+
64
+ if (isDev) {
65
+ throw new Error(errorMsg);
66
+ } else {
67
+ console.error(errorMsg);
68
+ }
69
+ }
70
+ return mapped || className;
71
+ };
72
+
73
+ const resolveAll = (classes: (string | undefined | null | false)[]): string => {
74
+ return classes
75
+ .filter(Boolean)
76
+ .map(c => resolve(c as string))
77
+ .join(' ');
78
+ };
79
+
80
+ return { resolve, resolveAll, mode: $finggu.mode, theme: $finggu.theme };
81
+ });
82
+ }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ export * from './context';
2
+ export * from './tabs-shared';
3
+
4
+ // Components
5
+ export { default as Button, __ffClasses_Button } from './Button.svelte';
6
+ export { default as Card, __ffClasses_Card } from './Card.svelte';
7
+ export { default as Input, __ffClasses_Input } from './Input.svelte';
8
+ export { default as Modal, __ffClasses_Modal } from './Modal.svelte';
9
+ export { default as Tabs } from './Tabs.svelte';
10
+ export { default as TabList } from './TabList.svelte';
11
+ export { default as TabTrigger } from './TabTrigger.svelte';
12
+ export { default as TabContent } from './TabContent.svelte';
13
+ export { default as Dropdown, __ffClasses_Dropdown } from './Dropdown.svelte';
14
+ export { default as DropdownItem } from './DropdownItem.svelte';
15
+
16
+ // Re-export shared for manifest consistency
17
+ export { __ffClasses_Tabs } from './tabs-shared';
@@ -0,0 +1,15 @@
1
+ import { writable, type Writable } from 'svelte/store';
2
+
3
+ export const TABS_KEY = Symbol('FingguTabs');
4
+
5
+ export interface TabsContext {
6
+ activeTab: Writable<string>;
7
+ }
8
+
9
+ export const __ffClasses_Tabs = [
10
+ 'ff-tabs',
11
+ 'ff-tab-list',
12
+ 'ff-tab',
13
+ 'ff-tab-active',
14
+ 'ff-tab-content'
15
+ ];