@finggujadhav/react 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.
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
3
+ variant?: 'primary' | 'secondary' | 'ghost' | 'outline';
4
+ size?: 'sm' | 'md' | 'lg';
5
+ motion?: 'fade' | 'slide-up' | 'scale-in' | 'lift';
6
+ glass?: boolean;
7
+ }
8
+ /**
9
+ * Static manifest of all classes used by Button.
10
+ * Used by compiler for deterministic tree-shaking regardless of build order.
11
+ */
12
+ export declare const __ffClasses_Button: string[];
13
+ /**
14
+ * Finggu Button Component
15
+ * Maps props to deterministic ff-* classes or hashed equivalents.
16
+ */
17
+ export declare const Button: React.FC<ButtonProps>;
18
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../src/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,WAAY,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IAC9E,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAAC;IACxD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAsBD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,UAM9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAyBxC,CAAC"}
package/dist/button.js ADDED
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFinggu } from './provider';
3
+ const VARIANTS = {
4
+ primary: 'ff-btn-primary',
5
+ secondary: 'ff-btn-secondary',
6
+ ghost: 'ff-btn-ghost',
7
+ outline: 'ff-btn-outline'
8
+ };
9
+ const SIZES = {
10
+ sm: 'ff-btn-sm',
11
+ md: 'ff-btn-md',
12
+ lg: 'ff-btn-lg'
13
+ };
14
+ const MOTIONS = {
15
+ fade: 'ff-fade-in',
16
+ 'slide-up': 'ff-slide-up',
17
+ 'scale-in': 'ff-scale-in',
18
+ lift: 'ff-hover-lift'
19
+ };
20
+ /**
21
+ * Static manifest of all classes used by Button.
22
+ * Used by compiler for deterministic tree-shaking regardless of build order.
23
+ */
24
+ export const __ffClasses_Button = [
25
+ 'ff-btn',
26
+ ...Object.values(VARIANTS),
27
+ ...Object.values(SIZES),
28
+ ...Object.values(MOTIONS),
29
+ 'ff-card-glass'
30
+ ];
31
+ /**
32
+ * Finggu Button Component
33
+ * Maps props to deterministic ff-* classes or hashed equivalents.
34
+ */
35
+ export const Button = ({ variant = 'primary', size = 'md', motion, glass, className, children, ...props }) => {
36
+ const { resolveAll } = useFinggu();
37
+ const ffClasses = resolveAll([
38
+ 'ff-btn',
39
+ VARIANTS[variant],
40
+ SIZES[size],
41
+ glass && 'ff-card-glass',
42
+ motion && MOTIONS[motion],
43
+ className
44
+ ]);
45
+ return (_jsx("button", { className: ffClasses, ...props, children: children }));
46
+ };
package/dist/card.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ variant?: 'outline' | 'glass';
4
+ padding?: 'none' | 'sm' | 'md' | 'lg';
5
+ }
6
+ export declare const __ffClasses_Card: string[];
7
+ export declare const Card: React.FC<CardProps>;
8
+ export declare const CardHeader: React.FC<React.HTMLAttributes<HTMLDivElement>>;
9
+ export declare const CardBody: React.FC<React.HTMLAttributes<HTMLDivElement>>;
10
+ //# sourceMappingURL=card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../src/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACnE,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CACzC;AAcD,eAAO,MAAM,gBAAgB,UAM5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAqBpC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAGrE,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAGnE,CAAC"}
package/dist/card.js ADDED
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFinggu } from './provider';
3
+ const VARIANTS = {
4
+ outline: 'ff-card-outline',
5
+ glass: 'ff-card-glass'
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
+ };
13
+ export const __ffClasses_Card = [
14
+ 'ff-card',
15
+ 'ff-card-header',
16
+ 'ff-card-body',
17
+ ...Object.values(VARIANTS),
18
+ ...Object.values(PADDINGS)
19
+ ];
20
+ export const Card = ({ variant, padding = 'md', className, children, ...props }) => {
21
+ const { resolveAll } = useFinggu();
22
+ const ffClasses = resolveAll([
23
+ 'ff-card',
24
+ variant && VARIANTS[variant],
25
+ PADDINGS[padding],
26
+ className
27
+ ]);
28
+ return (_jsx("div", { className: ffClasses, ...props, children: children }));
29
+ };
30
+ export const CardHeader = ({ className, children, ...props }) => {
31
+ const { resolveAll } = useFinggu();
32
+ return _jsx("div", { className: resolveAll(['ff-card-header', className]), ...props, children: children });
33
+ };
34
+ export const CardBody = ({ className, children, ...props }) => {
35
+ const { resolveAll } = useFinggu();
36
+ return _jsx("div", { className: resolveAll(['ff-card-body', className]), ...props, children: children });
37
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ export interface DropdownProps {
3
+ trigger: React.ReactNode;
4
+ children: React.ReactNode;
5
+ align?: 'left' | 'right';
6
+ }
7
+ export declare const __ffClasses_Dropdown: string[];
8
+ export declare const Dropdown: React.FC<DropdownProps>;
9
+ export declare const DropdownItem: React.FC<React.HTMLAttributes<HTMLDivElement>>;
10
+ //# sourceMappingURL=dropdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropdown.d.ts","sourceRoot":"","sources":["../src/dropdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAG3D,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED,eAAO,MAAM,oBAAoB,UAMhC,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAuC5C,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAGvE,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { useFinggu } from './provider';
4
+ export const __ffClasses_Dropdown = [
5
+ 'ff-dropdown',
6
+ 'ff-dropdown-trigger',
7
+ 'ff-dropdown-menu',
8
+ 'ff-dropdown-menu-right',
9
+ 'ff-dropdown-item'
10
+ ];
11
+ export const Dropdown = ({ trigger, children, align = 'left' }) => {
12
+ const [isOpen, setIsOpen] = useState(false);
13
+ const containerRef = useRef(null);
14
+ const { resolveAll } = useFinggu();
15
+ useEffect(() => {
16
+ const handleClickOutside = (event) => {
17
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
18
+ setIsOpen(false);
19
+ }
20
+ };
21
+ document.addEventListener('mousedown', handleClickOutside);
22
+ return () => document.removeEventListener('mousedown', handleClickOutside);
23
+ }, []);
24
+ return (_jsxs("div", { className: resolveAll(['ff-dropdown']), ref: containerRef, children: [_jsx("button", { type: "button", className: resolveAll(['ff-dropdown-trigger']), onClick: () => setIsOpen(!isOpen), "aria-haspopup": "true", "aria-expanded": isOpen, children: trigger }), _jsx("div", { className: resolveAll([
25
+ 'ff-dropdown-menu',
26
+ align === 'right' && 'ff-dropdown-menu-right'
27
+ ]), "data-ff-state": isOpen ? 'open' : 'closed', role: "menu", "aria-hidden": !isOpen, children: children })] }));
28
+ };
29
+ export const DropdownItem = ({ className, children, ...props }) => {
30
+ const { resolveAll } = useFinggu();
31
+ return _jsx("div", { className: resolveAll(['ff-dropdown-item', className]), ...props, children: children });
32
+ };
@@ -0,0 +1,8 @@
1
+ export * from './provider';
2
+ export * from './button';
3
+ export * from './card';
4
+ export * from './input';
5
+ export * from './modal';
6
+ export * from './tabs';
7
+ export * from './dropdown';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from './provider';
2
+ export * from './button';
3
+ export * from './card';
4
+ export * from './input';
5
+ export * from './modal';
6
+ export * from './tabs';
7
+ export * from './dropdown';
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
3
+ error?: boolean;
4
+ }
5
+ export declare const __ffClasses_Input: string[];
6
+ export declare const Input: React.FC<InputProps>;
7
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC;IAC3E,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,iBAAiB,UAG7B,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAUtC,CAAC"}
package/dist/input.js ADDED
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFinggu } from './provider';
3
+ export const __ffClasses_Input = [
4
+ 'ff-input',
5
+ 'ff-input-error'
6
+ ];
7
+ export const Input = ({ error, className, ...props }) => {
8
+ const { resolveAll } = useFinggu();
9
+ const ffClasses = resolveAll([
10
+ 'ff-input',
11
+ error && 'ff-input-error',
12
+ className
13
+ ]);
14
+ return _jsx("input", { className: ffClasses, ...props });
15
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ export interface ModalProps {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ children: React.ReactNode;
6
+ className?: string;
7
+ }
8
+ export declare const __ffClasses_Modal: string[];
9
+ export declare const Modal: React.FC<ModalProps>;
10
+ //# sourceMappingURL=modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../src/modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,MAAM,WAAW,UAAU;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,iBAAiB,UAM7B,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA4BtC,CAAC"}
package/dist/modal.js ADDED
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { useFinggu } from './provider';
4
+ export const __ffClasses_Modal = [
5
+ 'ff-modal',
6
+ 'ff-modal-open',
7
+ 'ff-modal-closed',
8
+ 'ff-modal-overlay',
9
+ 'ff-modal-content'
10
+ ];
11
+ export const Modal = ({ isOpen, onClose, children, className }) => {
12
+ const { resolveAll } = useFinggu();
13
+ const [mounted, setMounted] = useState(false);
14
+ useEffect(() => {
15
+ if (isOpen) {
16
+ setMounted(true);
17
+ document.body.style.overflow = 'hidden';
18
+ }
19
+ else {
20
+ const timer = setTimeout(() => setMounted(false), 300); // Wait for exit animation
21
+ document.body.style.overflow = '';
22
+ return () => clearTimeout(timer);
23
+ }
24
+ }, [isOpen]);
25
+ if (!mounted && !isOpen)
26
+ return null;
27
+ return (_jsxs("div", { className: resolveAll(['ff-modal', isOpen ? 'ff-modal-open' : 'ff-modal-closed']), "aria-hidden": !isOpen, children: [_jsx("div", { className: "ff-modal-overlay", onClick: onClose }), _jsx("div", { className: resolveAll(['ff-modal-content', className]), children: children })] }));
28
+ };
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { FingguTheme } from '@finggujadhav/js-helper';
3
+ export interface FingguMapping {
4
+ _version?: string;
5
+ [key: string]: string | undefined;
6
+ }
7
+ export interface FingguProviderProps {
8
+ children: React.ReactNode;
9
+ mapping?: FingguMapping;
10
+ mode?: 'dev' | 'opt' | 'ext';
11
+ version?: string;
12
+ theme?: FingguTheme;
13
+ }
14
+ /**
15
+ * Provides FingguFlux class mapping to the component tree.
16
+ */
17
+ export declare const FingguProvider: React.FC<FingguProviderProps>;
18
+ /**
19
+ * Hook to resolve FingguFlux classes to their mapped versions.
20
+ */
21
+ export declare const useFinggu: () => {
22
+ resolve: (className: string) => string;
23
+ resolveAll: (classes: (string | undefined | null | false)[]) => string;
24
+ mode: "dev" | "opt" | "ext";
25
+ theme: FingguTheme | undefined;
26
+ };
27
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgE,MAAM,OAAO,CAAC;AACrF,OAAO,EAAY,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAcD,MAAM,WAAW,mBAAmB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+BxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS;yBAGU,MAAM,KAAG,MAAM;0BAed,CAAC,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC,EAAE,KAAG,MAAM;;;CAQ9E,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, useEffect, useRef } from 'react';
3
+ import { setTheme } from '@finggujadhav/js-helper';
4
+ const FingguContext = createContext({
5
+ mapping: null,
6
+ mode: 'dev'
7
+ });
8
+ /**
9
+ * Provides FingguFlux class mapping to the component tree.
10
+ */
11
+ export const FingguProvider = ({ children, mapping = null, mode = 'dev', version, theme = 'system' }) => {
12
+ const containerRef = useRef(null);
13
+ useMemo(() => {
14
+ if (mapping && version && mapping._version && mapping._version !== version) {
15
+ console.warn(`[FingguFlux] Version Mismatch: mapping.json (${mapping._version}) does not match expected CSS version (${version})`);
16
+ }
17
+ }, [mapping, version]);
18
+ // Apply theme to container for isolation
19
+ useEffect(() => {
20
+ if (containerRef.current) {
21
+ setTheme(theme, containerRef.current);
22
+ }
23
+ }, [theme]);
24
+ const value = useMemo(() => ({ mapping, mode, version, theme }), [mapping, mode, version, theme]);
25
+ return (_jsx(FingguContext.Provider, { value: value, children: _jsx("div", { ref: containerRef, style: { display: 'contents' }, children: children }) }));
26
+ };
27
+ /**
28
+ * Hook to resolve FingguFlux classes to their mapped versions.
29
+ */
30
+ export const useFinggu = () => {
31
+ const { mapping, mode, theme } = useContext(FingguContext);
32
+ const resolve = (className) => {
33
+ if (mode === 'dev' || !mapping)
34
+ return className;
35
+ const mapped = mapping[className];
36
+ if (mode === 'ext' && !mapped && className.startsWith('ff-')) {
37
+ const errorMsg = `[FingguFlux] Critical: Class '${className}' not found in mapping.json in Extreme mode. This will cause broken styles in production.`;
38
+ if (process.env.NODE_ENV === 'development') {
39
+ throw new Error(errorMsg);
40
+ }
41
+ else {
42
+ console.error(errorMsg);
43
+ }
44
+ }
45
+ return mapped || className;
46
+ };
47
+ const resolveAll = (classes) => {
48
+ return classes
49
+ .filter(Boolean)
50
+ .map(c => resolve(c))
51
+ .join(' ');
52
+ };
53
+ return { resolve, resolveAll, mode, theme };
54
+ };
package/dist/tabs.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ export interface TabsProps {
3
+ defaultValue: string;
4
+ children: React.ReactNode;
5
+ }
6
+ export declare const __ffClasses_Tabs: string[];
7
+ export declare const Tabs: React.FC<TabsProps>;
8
+ export declare const TabList: React.FC<{
9
+ children: React.ReactNode;
10
+ }>;
11
+ export declare const TabTrigger: React.FC<{
12
+ value: string;
13
+ children: React.ReactNode;
14
+ }>;
15
+ export declare const TabContent: React.FC<{
16
+ value: string;
17
+ children: React.ReactNode;
18
+ }>;
19
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../src/tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAUxC,MAAM,WAAW,SAAS;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAED,eAAO,MAAM,gBAAgB,UAM5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAOpC,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAE3D,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAe7E,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAI7E,CAAC"}
package/dist/tabs.js ADDED
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useState } from 'react';
3
+ import { useFinggu } from './provider';
4
+ const TabsContext = React.createContext(null);
5
+ export const __ffClasses_Tabs = [
6
+ 'ff-tabs',
7
+ 'ff-tab-list',
8
+ 'ff-tab',
9
+ 'ff-tab-active',
10
+ 'ff-tab-content'
11
+ ];
12
+ export const Tabs = ({ defaultValue, children }) => {
13
+ const [activeTab, setActiveTab] = useState(defaultValue);
14
+ return (_jsx(TabsContext.Provider, { value: { activeTab, setActiveTab }, children: _jsx("div", { className: "ff-tabs", children: children }) }));
15
+ };
16
+ export const TabList = ({ children }) => (_jsx("div", { className: "ff-tab-list", role: "tablist", children: children }));
17
+ export const TabTrigger = ({ value, children }) => {
18
+ const context = React.useContext(TabsContext);
19
+ const { resolveAll } = useFinggu();
20
+ if (!context)
21
+ return null;
22
+ return (_jsx("button", { role: "tab", "aria-selected": context.activeTab === value, className: resolveAll(['ff-tab', context.activeTab === value && 'ff-tab-active']), onClick: () => context.setActiveTab(value), children: children }));
23
+ };
24
+ export const TabContent = ({ value, children }) => {
25
+ const context = React.useContext(TabsContext);
26
+ if (!context || context.activeTab !== value)
27
+ return null;
28
+ return _jsx("div", { className: "ff-tab-content", children: children });
29
+ };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@finggujadhav/react",
3
+ "version": "0.9.0",
4
+ "description": "FingguFlux React Adapter - Zero-runtime, high-performance headless UI components.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "scripts": {
10
+ "build": "tsc"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src",
21
+ "!src/**/*.test.*",
22
+ "!src/**/__tests__"
23
+ ],
24
+ "dependencies": {
25
+ "@finggujadhav/core": "0.9.0",
26
+ "@finggujadhav/js-helper": "0.9.0"
27
+ },
28
+ "peerDependencies": {
29
+ "react": ">=16.8.0",
30
+ "react-dom": ">=16.8.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "^18.0.0",
34
+ "@types/react-dom": "^18.0.0",
35
+ "typescript": "^5.0.0"
36
+ }
37
+ }
package/src/button.tsx ADDED
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import { useFinggu } from './provider';
3
+
4
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: 'primary' | 'secondary' | 'ghost' | 'outline';
6
+ size?: 'sm' | 'md' | 'lg';
7
+ motion?: 'fade' | 'slide-up' | 'scale-in' | 'lift';
8
+ glass?: boolean;
9
+ }
10
+
11
+ const VARIANTS = {
12
+ primary: 'ff-btn-primary',
13
+ secondary: 'ff-btn-secondary',
14
+ ghost: 'ff-btn-ghost',
15
+ outline: 'ff-btn-outline'
16
+ };
17
+
18
+ const SIZES = {
19
+ sm: 'ff-btn-sm',
20
+ md: 'ff-btn-md',
21
+ lg: 'ff-btn-lg'
22
+ };
23
+
24
+ const MOTIONS = {
25
+ fade: 'ff-fade-in',
26
+ 'slide-up': 'ff-slide-up',
27
+ 'scale-in': 'ff-scale-in',
28
+ lift: 'ff-hover-lift'
29
+ };
30
+
31
+ /**
32
+ * Static manifest of all classes used by Button.
33
+ * Used by compiler for deterministic tree-shaking regardless of build order.
34
+ */
35
+ export const __ffClasses_Button = [
36
+ 'ff-btn',
37
+ ...Object.values(VARIANTS),
38
+ ...Object.values(SIZES),
39
+ ...Object.values(MOTIONS),
40
+ 'ff-card-glass'
41
+ ];
42
+
43
+ /**
44
+ * Finggu Button Component
45
+ * Maps props to deterministic ff-* classes or hashed equivalents.
46
+ */
47
+ export const Button: React.FC<ButtonProps> = ({
48
+ variant = 'primary',
49
+ size = 'md',
50
+ motion,
51
+ glass,
52
+ className,
53
+ children,
54
+ ...props
55
+ }) => {
56
+ const { resolveAll } = useFinggu();
57
+
58
+ const ffClasses = resolveAll([
59
+ 'ff-btn',
60
+ VARIANTS[variant],
61
+ SIZES[size],
62
+ glass && 'ff-card-glass',
63
+ motion && MOTIONS[motion],
64
+ className
65
+ ]);
66
+
67
+ return (
68
+ <button className={ffClasses} {...props}>
69
+ {children}
70
+ </button>
71
+ );
72
+ };
package/src/card.tsx ADDED
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import { useFinggu } from './provider';
3
+
4
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ variant?: 'outline' | 'glass';
6
+ padding?: 'none' | 'sm' | 'md' | 'lg';
7
+ }
8
+
9
+ const VARIANTS = {
10
+ outline: 'ff-card-outline',
11
+ glass: 'ff-card-glass'
12
+ };
13
+
14
+ const PADDINGS = {
15
+ none: 'ff-p-0',
16
+ sm: 'ff-p-2',
17
+ md: 'ff-p-4',
18
+ lg: 'ff-p-8'
19
+ };
20
+
21
+ export const __ffClasses_Card = [
22
+ 'ff-card',
23
+ 'ff-card-header',
24
+ 'ff-card-body',
25
+ ...Object.values(VARIANTS),
26
+ ...Object.values(PADDINGS)
27
+ ];
28
+
29
+ export const Card: React.FC<CardProps> = ({
30
+ variant,
31
+ padding = 'md',
32
+ className,
33
+ children,
34
+ ...props
35
+ }) => {
36
+ const { resolveAll } = useFinggu();
37
+
38
+ const ffClasses = resolveAll([
39
+ 'ff-card',
40
+ variant && VARIANTS[variant],
41
+ PADDINGS[padding],
42
+ className
43
+ ]);
44
+
45
+ return (
46
+ <div className={ffClasses} {...props}>
47
+ {children}
48
+ </div>
49
+ );
50
+ };
51
+
52
+ export const CardHeader: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, children, ...props }) => {
53
+ const { resolveAll } = useFinggu();
54
+ return <div className={resolveAll(['ff-card-header', className])} {...props}>{children}</div>;
55
+ };
56
+
57
+ export const CardBody: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, children, ...props }) => {
58
+ const { resolveAll } = useFinggu();
59
+ return <div className={resolveAll(['ff-card-body', className])} {...props}>{children}</div>;
60
+ };
@@ -0,0 +1,62 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import { useFinggu } from './provider';
3
+
4
+ export interface DropdownProps {
5
+ trigger: React.ReactNode;
6
+ children: React.ReactNode;
7
+ align?: 'left' | 'right';
8
+ }
9
+
10
+ export const __ffClasses_Dropdown = [
11
+ 'ff-dropdown',
12
+ 'ff-dropdown-trigger',
13
+ 'ff-dropdown-menu',
14
+ 'ff-dropdown-menu-right',
15
+ 'ff-dropdown-item'
16
+ ];
17
+
18
+ export const Dropdown: React.FC<DropdownProps> = ({ trigger, children, align = 'left' }) => {
19
+ const [isOpen, setIsOpen] = useState(false);
20
+ const containerRef = useRef<HTMLDivElement>(null);
21
+ const { resolveAll } = useFinggu();
22
+
23
+ useEffect(() => {
24
+ const handleClickOutside = (event: MouseEvent) => {
25
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
26
+ setIsOpen(false);
27
+ }
28
+ };
29
+ document.addEventListener('mousedown', handleClickOutside);
30
+ return () => document.removeEventListener('mousedown', handleClickOutside);
31
+ }, []);
32
+
33
+ return (
34
+ <div className={resolveAll(['ff-dropdown'])} ref={containerRef}>
35
+ <button
36
+ type="button"
37
+ className={resolveAll(['ff-dropdown-trigger'])}
38
+ onClick={() => setIsOpen(!isOpen)}
39
+ aria-haspopup="true"
40
+ aria-expanded={isOpen}
41
+ >
42
+ {trigger}
43
+ </button>
44
+ <div
45
+ className={resolveAll([
46
+ 'ff-dropdown-menu',
47
+ align === 'right' && 'ff-dropdown-menu-right'
48
+ ])}
49
+ data-ff-state={isOpen ? 'open' : 'closed'}
50
+ role="menu"
51
+ aria-hidden={!isOpen}
52
+ >
53
+ {children}
54
+ </div>
55
+ </div>
56
+ );
57
+ };
58
+
59
+ export const DropdownItem: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, children, ...props }) => {
60
+ const { resolveAll } = useFinggu();
61
+ return <div className={resolveAll(['ff-dropdown-item', className])} {...props}>{children}</div>;
62
+ };
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './provider';
2
+ export * from './button';
3
+ export * from './card';
4
+ export * from './input';
5
+ export * from './modal';
6
+ export * from './tabs';
7
+ export * from './dropdown';
package/src/input.tsx ADDED
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { useFinggu } from './provider';
3
+
4
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
5
+ error?: boolean;
6
+ }
7
+
8
+ export const __ffClasses_Input = [
9
+ 'ff-input',
10
+ 'ff-input-error'
11
+ ];
12
+
13
+ export const Input: React.FC<InputProps> = ({ error, className, ...props }) => {
14
+ const { resolveAll } = useFinggu();
15
+
16
+ const ffClasses = resolveAll([
17
+ 'ff-input',
18
+ error && 'ff-input-error',
19
+ className
20
+ ]);
21
+
22
+ return <input className={ffClasses} {...props} />;
23
+ };
package/src/modal.tsx ADDED
@@ -0,0 +1,47 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useFinggu } from './provider';
3
+
4
+ export interface ModalProps {
5
+ isOpen: boolean;
6
+ onClose: () => void;
7
+ children: React.ReactNode;
8
+ className?: string;
9
+ }
10
+
11
+ export const __ffClasses_Modal = [
12
+ 'ff-modal',
13
+ 'ff-modal-open',
14
+ 'ff-modal-closed',
15
+ 'ff-modal-overlay',
16
+ 'ff-modal-content'
17
+ ];
18
+
19
+ export const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children, className }) => {
20
+ const { resolveAll } = useFinggu();
21
+ const [mounted, setMounted] = useState(false);
22
+
23
+ useEffect(() => {
24
+ if (isOpen) {
25
+ setMounted(true);
26
+ document.body.style.overflow = 'hidden';
27
+ } else {
28
+ const timer = setTimeout(() => setMounted(false), 300); // Wait for exit animation
29
+ document.body.style.overflow = '';
30
+ return () => clearTimeout(timer);
31
+ }
32
+ }, [isOpen]);
33
+
34
+ if (!mounted && !isOpen) return null;
35
+
36
+ return (
37
+ <div
38
+ className={resolveAll(['ff-modal', isOpen ? 'ff-modal-open' : 'ff-modal-closed'])}
39
+ aria-hidden={!isOpen}
40
+ >
41
+ <div className="ff-modal-overlay" onClick={onClose} />
42
+ <div className={resolveAll(['ff-modal-content', className])}>
43
+ {children}
44
+ </div>
45
+ </div>
46
+ );
47
+ };
@@ -0,0 +1,94 @@
1
+ import React, { createContext, useContext, useMemo, useEffect, useRef } from 'react';
2
+ import { setTheme, FingguTheme } from '@finggujadhav/js-helper';
3
+
4
+ export interface FingguMapping {
5
+ _version?: string;
6
+ [key: string]: string | undefined;
7
+ }
8
+
9
+ interface FingguContextValue {
10
+ mapping: FingguMapping | null;
11
+ mode: 'dev' | 'opt' | 'ext';
12
+ version?: string;
13
+ theme?: FingguTheme;
14
+ }
15
+
16
+ const FingguContext = createContext<FingguContextValue>({
17
+ mapping: null,
18
+ mode: 'dev'
19
+ });
20
+
21
+ export interface FingguProviderProps {
22
+ children: React.ReactNode;
23
+ mapping?: FingguMapping;
24
+ mode?: 'dev' | 'opt' | 'ext';
25
+ version?: string; // Target CSS version to validate against
26
+ theme?: FingguTheme;
27
+ }
28
+
29
+ /**
30
+ * Provides FingguFlux class mapping to the component tree.
31
+ */
32
+ export const FingguProvider: React.FC<FingguProviderProps> = ({
33
+ children,
34
+ mapping = null,
35
+ mode = 'dev',
36
+ version,
37
+ theme = 'system'
38
+ }) => {
39
+ const containerRef = useRef<HTMLDivElement>(null);
40
+
41
+ useMemo(() => {
42
+ if (mapping && version && mapping._version && mapping._version !== version) {
43
+ console.warn(`[FingguFlux] Version Mismatch: mapping.json (${mapping._version}) does not match expected CSS version (${version})`);
44
+ }
45
+ }, [mapping, version]);
46
+
47
+ // Apply theme to container for isolation
48
+ useEffect(() => {
49
+ if (containerRef.current) {
50
+ setTheme(theme, containerRef.current);
51
+ }
52
+ }, [theme]);
53
+
54
+ const value = useMemo(() => ({ mapping, mode, version, theme }), [mapping, mode, version, theme]);
55
+
56
+ return (
57
+ <FingguContext.Provider value={value}>
58
+ <div ref={containerRef} style={{ display: 'contents' }}>
59
+ {children}
60
+ </div>
61
+ </FingguContext.Provider>
62
+ );
63
+ };
64
+
65
+ /**
66
+ * Hook to resolve FingguFlux classes to their mapped versions.
67
+ */
68
+ export const useFinggu = () => {
69
+ const { mapping, mode, theme } = useContext(FingguContext);
70
+
71
+ const resolve = (className: string): string => {
72
+ if (mode === 'dev' || !mapping) return className;
73
+
74
+ const mapped = mapping[className];
75
+ if (mode === 'ext' && !mapped && className.startsWith('ff-')) {
76
+ const errorMsg = `[FingguFlux] Critical: Class '${className}' not found in mapping.json in Extreme mode. This will cause broken styles in production.`;
77
+ if (process.env.NODE_ENV === 'development') {
78
+ throw new Error(errorMsg);
79
+ } else {
80
+ console.error(errorMsg);
81
+ }
82
+ }
83
+ return mapped || className;
84
+ };
85
+
86
+ const resolveAll = (classes: (string | undefined | null | false)[]): string => {
87
+ return classes
88
+ .filter(Boolean)
89
+ .map(c => resolve(c as string))
90
+ .join(' ');
91
+ };
92
+
93
+ return { resolve, resolveAll, mode, theme };
94
+ };
package/src/tabs.tsx ADDED
@@ -0,0 +1,58 @@
1
+ import React, { useState } from 'react';
2
+ import { useFinggu } from './provider';
3
+
4
+ interface TabsContextValue {
5
+ activeTab: string;
6
+ setActiveTab: (id: string) => void;
7
+ }
8
+
9
+ const TabsContext = React.createContext<TabsContextValue | null>(null);
10
+
11
+ export interface TabsProps {
12
+ defaultValue: string;
13
+ children: React.ReactNode;
14
+ }
15
+
16
+ export const __ffClasses_Tabs = [
17
+ 'ff-tabs',
18
+ 'ff-tab-list',
19
+ 'ff-tab',
20
+ 'ff-tab-active',
21
+ 'ff-tab-content'
22
+ ];
23
+
24
+ export const Tabs: React.FC<TabsProps> = ({ defaultValue, children }) => {
25
+ const [activeTab, setActiveTab] = useState(defaultValue);
26
+ return (
27
+ <TabsContext.Provider value={{ activeTab, setActiveTab }}>
28
+ <div className="ff-tabs">{children}</div>
29
+ </TabsContext.Provider>
30
+ );
31
+ };
32
+
33
+ export const TabList: React.FC<{ children: React.ReactNode }> = ({ children }) => (
34
+ <div className="ff-tab-list" role="tablist">{children}</div>
35
+ );
36
+
37
+ export const TabTrigger: React.FC<{ value: string; children: React.ReactNode }> = ({ value, children }) => {
38
+ const context = React.useContext(TabsContext);
39
+ const { resolveAll } = useFinggu();
40
+ if (!context) return null;
41
+
42
+ return (
43
+ <button
44
+ role="tab"
45
+ aria-selected={context.activeTab === value}
46
+ className={resolveAll(['ff-tab', context.activeTab === value && 'ff-tab-active'])}
47
+ onClick={() => context.setActiveTab(value)}
48
+ >
49
+ {children}
50
+ </button>
51
+ );
52
+ };
53
+
54
+ export const TabContent: React.FC<{ value: string; children: React.ReactNode }> = ({ value, children }) => {
55
+ const context = React.useContext(TabsContext);
56
+ if (!context || context.activeTab !== value) return null;
57
+ return <div className="ff-tab-content">{children}</div>;
58
+ };