@kawaiininja/layouts 1.0.4 → 1.0.5

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/README.md CHANGED
@@ -36,7 +36,7 @@ High-performance, premium mobile-first layouts for the Onyx Framework. Designed
36
36
  ## 🚀 Installation
37
37
 
38
38
  ```bash
39
- npm install @onyx/layouts
39
+ npm install @kawaiininja/layouts
40
40
  ```
41
41
 
42
42
  Note: This package requires `framer-motion`, `lucide-react`, and `react` >= 18.0.0.
@@ -48,7 +48,7 @@ Note: This package requires `framer-motion`, `lucide-react`, and `react` >= 18.0
48
48
  ### Basic Example
49
49
 
50
50
  ```jsx
51
- import { OnyxMobileLayout } from "@onyx/layouts";
51
+ import { OnyxMobileLayout } from "@kawaiininja/layouts";
52
52
  import { Home, Search, Bell, User, PenTool, Grid } from "lucide-react";
53
53
 
54
54
  const MyApp = () => {
@@ -103,17 +103,43 @@ function useRailNavScroll(active, navKeys) {
103
103
  };
104
104
  }
105
105
  // --- Main Layout Component ---
106
- const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh, isRefreshing: externalRefreshing, rightAction, initialTab = "home", drawerItems = [], }) => {
107
- const [activeTab, setActiveTab] = useState(initialTab);
106
+ const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh, isRefreshing: externalRefreshing, rightAction, initialTab = "home", activeTab: externalActiveTab, activeSubTab: externalActiveSubTab, onNavigate, drawerItems = [], }) => {
107
+ const [internalActiveTab, setInternalActiveTab] = useState(initialTab);
108
+ const activeTab = externalActiveTab || internalActiveTab;
108
109
  const [isOpen, setIsOpen] = useState(false);
109
110
  const [isDragging, setIsDragging] = useState(false);
110
111
  const [activeDrawer, setActiveDrawer] = useState(null);
111
112
  const [pullY, setPullY] = useState(0);
112
113
  const [internalRefreshing, setInternalRefreshing] = useState(false);
113
114
  const currentTabConfig = tabs.find((t) => t.id === activeTab);
114
- const isRefreshing = currentTabConfig?.isRefreshing ?? externalRefreshing ?? internalRefreshing;
115
115
  const subTabs = currentTabConfig?.subTabs || [];
116
- const [subTab, setSubTab] = useState(subTabs[0]?.label || "");
116
+ const [internalSubTab, setInternalSubTab] = useState(subTabs[0]?.label || "");
117
+ const subTab = externalActiveSubTab || internalSubTab;
118
+ const navigateTo = (tabId, subTabLabel) => {
119
+ if (tabId)
120
+ setInternalActiveTab(tabId);
121
+ if (subTabLabel)
122
+ setInternalSubTab(subTabLabel);
123
+ if (onNavigate) {
124
+ const targetTab = tabs.find((t) => t.id === (tabId || activeTab));
125
+ let path = targetTab?.path || "";
126
+ if (subTabLabel) {
127
+ const st = targetTab?.subTabs.find((s) => s.label === subTabLabel);
128
+ if (st?.path) {
129
+ if (st.path.startsWith("/")) {
130
+ path = st.path;
131
+ }
132
+ else {
133
+ const base = path.endsWith("/") ? path : path + "/";
134
+ path = base + st.path;
135
+ }
136
+ }
137
+ }
138
+ if (path)
139
+ onNavigate(path);
140
+ }
141
+ };
142
+ const isRefreshing = currentTabConfig?.isRefreshing ?? externalRefreshing ?? internalRefreshing;
117
143
  const navKeys = useMemo(() => tabs.map((t) => t.id), [tabs]);
118
144
  const { scrollContainerRef, activeHeight, activeOffset, registerButtonRef } = useRailNavScroll(activeTab, navKeys);
119
145
  const DRAWER_WIDTH = 220;
@@ -165,8 +191,8 @@ const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh,
165
191
  useEffect(() => {
166
192
  if (currentTabConfig && currentTabConfig.subTabs.length > 0) {
167
193
  const isValid = currentTabConfig.subTabs.some((st) => st.label === subTab);
168
- if (!isValid)
169
- setSubTab(currentTabConfig.subTabs[0].label);
194
+ if (!isValid && currentTabConfig.subTabs.length > 0)
195
+ navigateTo(undefined, currentTabConfig.subTabs[0].label);
170
196
  }
171
197
  }, [activeTab, tabs, subTab, currentTabConfig]);
172
198
  const [[prevActive, direction], setDir] = useState([activeTab, 0]);
@@ -210,10 +236,7 @@ const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh,
210
236
  targetTab: tabs[0].id,
211
237
  targetSubTab: st.label,
212
238
  }))).map((item) => (_jsxs("button", { onClick: () => {
213
- if (item.targetTab)
214
- setActiveTab(item.targetTab);
215
- if (item.targetSubTab)
216
- setSubTab(item.targetSubTab);
239
+ navigateTo(item.targetTab, item.targetSubTab);
217
240
  if (item.onClick)
218
241
  item.onClick({
219
242
  openDrawer: (id) => setActiveDrawer(id),
@@ -280,9 +303,9 @@ const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh,
280
303
  if (Math.abs(lastDxRef.current) > 50) {
281
304
  const idx = subTabs.findIndex((t) => t.label === subTab);
282
305
  if (lastDxRef.current < 0 && idx < subTabs.length - 1)
283
- setSubTab(subTabs[idx + 1].label);
306
+ navigateTo(undefined, subTabs[idx + 1].label);
284
307
  else if (lastDxRef.current > 0 && idx > 0)
285
- setSubTab(subTabs[idx - 1].label);
308
+ navigateTo(undefined, subTabs[idx - 1].label);
286
309
  }
287
310
  }
288
311
  if (isVerticalPull.current) {
@@ -365,7 +388,7 @@ const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh,
365
388
  setQuickMenu((prev) => ({ ...prev, visible: false, selectedIndex: -1 }));
366
389
  }
367
390
  else {
368
- setActiveTab(tabId);
391
+ navigateTo(tabId);
369
392
  }
370
393
  };
371
394
  const currentTranslate = isDragging ? renderDragX : isOpen ? DRAWER_WIDTH : 0;
@@ -377,7 +400,7 @@ const OnyxMobileLayoutBase = ({ tabs, user, drawers = {}, onSignOut, onRefresh,
377
400
  ? "none"
378
401
  : "transform 0.3s cubic-bezier(0.32, 0.72, 0, 1), border-radius 0.3s",
379
402
  overflow: "hidden",
380
- }, children: [isOpen && !isDragging && (_jsx("div", { className: "absolute inset-0 z-50 bg-black/20", onClick: () => setIsOpen(false) })), _jsxs("div", { className: "flex-1 flex flex-col h-full mr-12 relative bg-[rgb(var(--bg-main))]", children: [_jsx(Header, { title: currentTabConfig?.navTitle || currentTabConfig?.label || "App", onMenuClick: () => setIsOpen(!isOpen), rightAction: currentTabConfig?.rightAction || rightAction }), _jsx(HorizontalTabs, { tabs: subTabs, active: subTab, onChange: setSubTab }), _jsxs("main", { ref: mainScrollRef, className: "flex-1 overflow-y-auto no-scrollbar overscroll-contain relative mr-4", children: [_jsx("div", { className: "absolute top-0 left-0 right-0 flex justify-center items-center pointer-events-none z-0", style: {
403
+ }, children: [isOpen && !isDragging && (_jsx("div", { className: "absolute inset-0 z-50 bg-black/20", onClick: () => setIsOpen(false) })), _jsxs("div", { className: "flex-1 flex flex-col h-full mr-12 relative bg-[rgb(var(--bg-main))]", children: [_jsx(Header, { title: currentTabConfig?.navTitle || currentTabConfig?.label || "App", onMenuClick: () => setIsOpen(!isOpen), rightAction: currentTabConfig?.rightAction || rightAction }), _jsx(HorizontalTabs, { tabs: subTabs, active: subTab, onChange: (label) => navigateTo(undefined, label) }), _jsxs("main", { ref: mainScrollRef, className: "flex-1 overflow-y-auto no-scrollbar overscroll-contain relative mr-4", children: [_jsx("div", { className: "absolute top-0 left-0 right-0 flex justify-center items-center pointer-events-none z-0", style: {
381
404
  height: `${pullY}px`,
382
405
  opacity: Math.min(pullY / 40, 1),
383
406
  }, children: _jsx("div", { className: `p-2 bg-[rgb(var(--bg-surface))] rounded-full shadow-md border border-[rgb(var(--color-border-subtle))] ${isRefreshing
package/dist/types.d.ts CHANGED
@@ -3,6 +3,7 @@ export interface SubTabConfig {
3
3
  label: string;
4
4
  icon: ComponentType<any>;
5
5
  view: ComponentType<any>;
6
+ path?: string;
6
7
  }
7
8
  export interface QuickActionConfig {
8
9
  label: string;
@@ -16,6 +17,7 @@ export interface TabConfig {
16
17
  label: string;
17
18
  icon: ComponentType<any>;
18
19
  navTitle?: string;
20
+ path?: string;
19
21
  subTabs: SubTabConfig[];
20
22
  quickActions: QuickActionConfig[];
21
23
  rightAction?: ReactNode;
@@ -50,5 +52,8 @@ export interface OnyxMobileLayoutProps {
50
52
  isRefreshing?: boolean;
51
53
  rightAction?: ReactNode;
52
54
  initialTab?: string;
55
+ activeTab?: string;
56
+ activeSubTab?: string;
57
+ onNavigate?: (path: string) => void;
53
58
  drawerItems?: DrawerItemConfig[];
54
59
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kawaiininja/layouts",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "High-performance, premium mobile-first layouts for the Onyx Framework, featuring gesture-driven navigation, radial quick actions, and integrated theme support.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -26,13 +26,13 @@
26
26
  "license": "MIT",
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": "https://github.com/kawaiininja/onyx-framework.git",
29
+ "url": "https://github.com/4kawaiininja/onyx-framework.git",
30
30
  "directory": "layouts"
31
31
  },
32
32
  "bugs": {
33
- "url": "https://github.com/kawaiininja/onyx-framework/issues"
33
+ "url": "https://github.com/4kawaiininja/onyx-framework/issues"
34
34
  },
35
- "homepage": "https://github.com/kawaiininja/onyx-framework#readme",
35
+ "homepage": "https://github.com/4kawaiininja/onyx-framework/blob/main/layouts/README.md",
36
36
  "exports": {
37
37
  ".": {
38
38
  "types": "./dist/index.d.ts",