@kawaiininja/layouts 1.0.3 → 1.0.4
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 +138 -59
- package/dist/types.d.ts +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,14 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
High-performance, premium mobile-first layouts for the Onyx Framework. Designed with a focus on fluid gestures, modularity, and state-of-the-art aesthetics.
|
|
4
4
|
|
|
5
|
+
[**📖 Read the Full Developer Guide**](./GUIDE.md) | [**🎨 Explore Examples**](./examples/)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
5
9
|
## ✨ Features
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
|
|
11
|
+
### 🖐️ Gesture-Driven Navigation (Fluid Flow)
|
|
12
|
+
|
|
13
|
+
- **Horizontal Tab Swiping**: Seamlessly transition between sub-tabs with natural swipe gestures. Built on a custom gesture engine for zero-lag response.
|
|
14
|
+
- **Vertical Pull-to-Refresh**: Per-tab or global refresh logic with integrated spring physics and haptic feedback support.
|
|
15
|
+
- **Smart History management**: Integrated hardware back-button handling. Pressing "Back" on Android or using back gestures will close drawers and panels before navigating away from the page.
|
|
16
|
+
|
|
17
|
+
### 🔘 Radial Quick Actions (Long-Press)
|
|
18
|
+
|
|
19
|
+
- **Zero-Friction Access**: Long-press any navigation rail item to reveal a radial selection menu.
|
|
20
|
+
- **Directional Selection**: Swipe towards an action item to select and execute it instantly without lifting your finger.
|
|
21
|
+
- **Programmable Logic**: Quick actions can trigger internal state changes, external redirects, or open custom layout drawers.
|
|
22
|
+
|
|
23
|
+
### 🖼️ Modular Layout Engine
|
|
24
|
+
|
|
25
|
+
- **Dynamic Headers**: Auto-syncing header titles with current navigation state. Supports custom right-aligned actions (buttons, icons, etc.).
|
|
26
|
+
- **Flexible Side Drawer**: Fully configurable drawer menu with support for deep-linking (target specific tabs/sub-tabs) and custom action links.
|
|
27
|
+
- **Panel System**: Register any number of custom drawers (Bottom Sheets) that can be triggered from anywhere in the app.
|
|
28
|
+
|
|
29
|
+
### 🎨 Design System & Theme
|
|
30
|
+
|
|
31
|
+
- **Premium Glassmorphism**: High-quality backdrop blurs and subtle gradients for a modern, high-end feel.
|
|
32
|
+
- **Integrated Theme Support**: Robust dark/light mode toggle with local storage persistence and system-aware defaults.
|
|
33
|
+
|
|
34
|
+
---
|
|
13
35
|
|
|
14
36
|
## 🚀 Installation
|
|
15
37
|
|
|
@@ -19,91 +41,148 @@ npm install @onyx/layouts
|
|
|
19
41
|
|
|
20
42
|
Note: This package requires `framer-motion`, `lucide-react`, and `react` >= 18.0.0.
|
|
21
43
|
|
|
44
|
+
---
|
|
45
|
+
|
|
22
46
|
## 📦 Usage
|
|
23
47
|
|
|
48
|
+
### Basic Example
|
|
49
|
+
|
|
24
50
|
```jsx
|
|
25
51
|
import { OnyxMobileLayout } from "@onyx/layouts";
|
|
26
|
-
import { Home,
|
|
52
|
+
import { Home, Search, Bell, User, PenTool, Grid } from "lucide-react";
|
|
27
53
|
|
|
28
|
-
const
|
|
54
|
+
const MyApp = () => {
|
|
29
55
|
const tabs = [
|
|
30
56
|
{
|
|
31
57
|
id: "home",
|
|
32
|
-
icon: Home,
|
|
33
58
|
label: "Home",
|
|
34
|
-
|
|
35
|
-
|
|
59
|
+
icon: Home,
|
|
60
|
+
navTitle: "Activity Feed",
|
|
61
|
+
subTabs: [
|
|
62
|
+
{ label: "Inbox", icon: Grid, view: () => <div>Your Messages</div> },
|
|
63
|
+
],
|
|
36
64
|
quickActions: [
|
|
37
65
|
{
|
|
66
|
+
label: "New Post",
|
|
38
67
|
icon: PenTool,
|
|
39
|
-
|
|
40
|
-
onClick: ({ openDrawer }) => openDrawer("editor"),
|
|
68
|
+
onClick: ({ openDrawer }) => openDrawer("post_editor"),
|
|
41
69
|
},
|
|
42
70
|
],
|
|
43
|
-
onRefresh: () => fetchData(),
|
|
44
|
-
isRefreshing: loadingState,
|
|
45
71
|
},
|
|
46
72
|
];
|
|
47
73
|
|
|
48
74
|
return (
|
|
49
75
|
<OnyxMobileLayout
|
|
50
76
|
tabs={tabs}
|
|
51
|
-
user={{
|
|
77
|
+
user={{
|
|
78
|
+
name: "Alex Designer",
|
|
79
|
+
handle: "@alex_ui",
|
|
80
|
+
avatar: "https://example.com/avatar.png",
|
|
81
|
+
}}
|
|
52
82
|
drawers={{
|
|
53
|
-
|
|
83
|
+
post_editor: PostEditorPanel,
|
|
54
84
|
}}
|
|
55
85
|
/>
|
|
56
86
|
);
|
|
57
87
|
};
|
|
58
88
|
```
|
|
59
89
|
|
|
90
|
+
---
|
|
91
|
+
|
|
60
92
|
## 🛠️ Configuration API
|
|
61
93
|
|
|
62
|
-
### OnyxMobileLayoutProps
|
|
63
|
-
|
|
64
|
-
| Prop | Type | Description
|
|
65
|
-
| :------------- | :-------------------------- |
|
|
66
|
-
| `tabs` | `TabConfig[]` |
|
|
67
|
-
| `user` | `UserConfig` |
|
|
68
|
-
| `drawers` | `Record<string, Component>` | Dictionary of custom
|
|
69
|
-
| `drawerItems` | `DrawerItemConfig[]` | Custom links for the
|
|
70
|
-
| `onSignOut` | `() => void` |
|
|
71
|
-
| `onRefresh` | `() => void` |
|
|
72
|
-
| `isRefreshing` | `boolean` |
|
|
73
|
-
| `initialTab` | `string` | ID of the tab to show
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
| Field | Type | Description |
|
|
78
|
-
| :------------- | :-------------------- | :------------------------------------------------ |
|
|
79
|
-
| `id` | `string` | Unique identifier for navigation. |
|
|
80
|
-
| `icon` | `LucideIcon` | Icon for the navigation rail. |
|
|
81
|
-
| `label` | `string` | Label for the navigation rail. |
|
|
82
|
-
| `navTitle` | `string` | (Optional) Title shown in the header when active. |
|
|
83
|
-
| `subTabs` | `SubTabConfig[]` | Array of nested horizontal tabs. |
|
|
84
|
-
| `quickActions` | `QuickActionConfig[]` | Actions triggered by long-press on the nav key. |
|
|
85
|
-
| `onRefresh` | `() => void` | Tab-specific refresh callback. |
|
|
86
|
-
| `isRefreshing` | `boolean` | Tab-specific refresh state. |
|
|
87
|
-
|
|
88
|
-
### QuickActionConfig / DrawerItemConfig
|
|
89
|
-
|
|
90
|
-
Quick actions and Drawer items support an `onClick` callback that receives a context object:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
onClick: ({ openDrawer: (id: string) => void }) => void
|
|
94
|
-
```
|
|
94
|
+
### `OnyxMobileLayoutProps`
|
|
95
|
+
|
|
96
|
+
| Prop | Type | Description |
|
|
97
|
+
| :------------- | :-------------------------- | :---------------------------------------------------------------------------- |
|
|
98
|
+
| `tabs` | `TabConfig[]` | **Required**. The main navigation stack (Rails on the right). |
|
|
99
|
+
| `user` | `UserConfig` | **Required**. Data for the side drawer's profile section. |
|
|
100
|
+
| `drawers` | `Record<string, Component>` | Dictionary of custom panel components. Keys are used as IDs for `openDrawer`. |
|
|
101
|
+
| `drawerItems` | `DrawerItemConfig[]` | Custom links for the side menu. If empty, defaults to first tab's subtabs. |
|
|
102
|
+
| `onSignOut` | `() => void` | Triggered when the "Sign Out" button in the drawer is clicked. |
|
|
103
|
+
| `onRefresh` | `() => void` | Global pull-to-refresh handler. Overridden if a tab has its own `onRefresh`. |
|
|
104
|
+
| `isRefreshing` | `boolean` | Global refresh state. |
|
|
105
|
+
| `initialTab` | `string` | The ID of the tab to show initially. Default: `home`. |
|
|
106
|
+
| `rightAction` | `ReactNode` | Global action element shown in the header (e.g., Settings icon). |
|
|
107
|
+
|
|
108
|
+
### `TabConfig`
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
| Field | Type | Description |
|
|
111
|
+
| :------------- | :-------------------- | :-------------------------------------------------------------------------- |
|
|
112
|
+
| `id` | `string` | Unique identifier used for internal routing. |
|
|
113
|
+
| `label` | `string` | Text label shown in the Rail. |
|
|
114
|
+
| `icon` | `LucideIcon` | Icon shown in the Rail. |
|
|
115
|
+
| `navTitle` | `string` | Optional. Text shown in the top header when this tab is active. |
|
|
116
|
+
| `subTabs` | `SubTabConfig[]` | Horizontal navigation nested under this tab. |
|
|
117
|
+
| `quickActions` | `QuickActionConfig[]` | Radial menu items triggered by long-press. |
|
|
118
|
+
| `onRefresh` | `() => void` | Tab-specific refresh handler. If provided, disables the global `onRefresh`. |
|
|
119
|
+
| `isRefreshing` | `boolean` | Tab-specific loading state. |
|
|
120
|
+
| `rightAction` | `ReactNode` | Tab-specific header action. |
|
|
97
121
|
|
|
98
|
-
|
|
122
|
+
### `SubTabConfig`
|
|
123
|
+
|
|
124
|
+
| Field | Type | Description |
|
|
125
|
+
| :------ | :----------- | :--------------------------------------------------- |
|
|
126
|
+
| `label` | `string` | Text shown in the horizontal pill. |
|
|
127
|
+
| `icon` | `LucideIcon` | Icon next to the label. |
|
|
128
|
+
| `view` | `Component` | The component to render when this sub-tab is active. |
|
|
129
|
+
|
|
130
|
+
### `QuickActionConfig` & `DrawerItemConfig`
|
|
131
|
+
|
|
132
|
+
Both configurations share an `onClick` context provider:
|
|
133
|
+
|
|
134
|
+
| Prop | Type | Description |
|
|
135
|
+
| :------------- | :-------------- | :------------------------------------------------------------------------ |
|
|
136
|
+
| `label` | `string` | Item text. |
|
|
137
|
+
| `icon` | `LucideIcon` | Item icon. |
|
|
138
|
+
| `targetTab` | `string` | (Drawer only) Target Tab ID for navigation. |
|
|
139
|
+
| `targetSubTab` | `string` | (Drawer only) Target Sub-tab Label for deep-linking. |
|
|
140
|
+
| `onClick` | `(ctx) => void` | Custom callback. Context contains `{ openDrawer: (id: string) => void }`. |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 🌊 Gesture Interactions Guide
|
|
145
|
+
|
|
146
|
+
### Pull-to-Refresh
|
|
147
|
+
|
|
148
|
+
To enable the refresh indicator, simply provide an `onRefresh` callback. The indicator will appear when the user pulls down from the top of the scroll container.
|
|
149
|
+
|
|
150
|
+
- **Threshold**: 60px pull triggers the refresh.
|
|
151
|
+
- **State Control**: Use `isRefreshing` to let the layout know when the operation is complete.
|
|
152
|
+
|
|
153
|
+
### Quick Action Menu (Radial Selection)
|
|
154
|
+
|
|
155
|
+
1. **Trigger**: Press and hold any item in the right navigation rail for 400ms.
|
|
156
|
+
2. **Selection**: While holding, move your finger up or down. The selection indicator will follow.
|
|
157
|
+
3. **Execution**: Release your finger to execute the highlighted action.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🎨 Design System (CSS Tokens)
|
|
162
|
+
|
|
163
|
+
The layout is highly skinable using CSS variables. Override these in your root CSS:
|
|
164
|
+
|
|
165
|
+
```css
|
|
166
|
+
:root {
|
|
167
|
+
/* Backgrounds */
|
|
168
|
+
--bg-main: 0, 0, 0; /* Pure black */
|
|
169
|
+
--bg-surface: 18, 18, 18; /* Elevate surface */
|
|
170
|
+
--bg-elevated: 28, 28, 28; /* Drawer/Menus */
|
|
171
|
+
|
|
172
|
+
/* Brand */
|
|
173
|
+
--color-accent: 99, 102, 241; /* Primary brand color (Indigo) */
|
|
174
|
+
--color-secondary: 236, 72, 153;
|
|
175
|
+
|
|
176
|
+
/* Text */
|
|
177
|
+
--text-primary: 255, 255, 255;
|
|
178
|
+
--text-muted: 156, 163, 175;
|
|
179
|
+
|
|
180
|
+
/* Borders */
|
|
181
|
+
--color-border-subtle: 255, 255, 255, 0.1;
|
|
182
|
+
}
|
|
183
|
+
```
|
|
99
184
|
|
|
100
|
-
|
|
101
|
-
- `--bg-surface`: Header/Tab background
|
|
102
|
-
- `--bg-elevated`: Drawer/Overlay background
|
|
103
|
-
- `--color-accent`: Highlight/Active color
|
|
104
|
-
- `--text-primary`: Main text
|
|
105
|
-
- `--text-muted`: Secondary text
|
|
106
|
-
- `--color-border-subtle`: Borders and dividers
|
|
185
|
+
---
|
|
107
186
|
|
|
108
187
|
## ⚖️ License
|
|
109
188
|
|
package/dist/types.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ export interface SubTabConfig {
|
|
|
7
7
|
export interface QuickActionConfig {
|
|
8
8
|
label: string;
|
|
9
9
|
icon: ComponentType<any>;
|
|
10
|
-
onClick?: (
|
|
10
|
+
onClick?: (ctx: {
|
|
11
|
+
openDrawer: (id: string) => void;
|
|
12
|
+
}) => void;
|
|
11
13
|
}
|
|
12
14
|
export interface TabConfig {
|
|
13
15
|
id: string;
|
|
@@ -25,7 +27,9 @@ export interface DrawerItemConfig {
|
|
|
25
27
|
icon: any;
|
|
26
28
|
targetTab?: string;
|
|
27
29
|
targetSubTab?: string;
|
|
28
|
-
onClick?: (
|
|
30
|
+
onClick?: (ctx: {
|
|
31
|
+
openDrawer: (id: string) => void;
|
|
32
|
+
}) => void;
|
|
29
33
|
}
|
|
30
34
|
export interface UserConfig {
|
|
31
35
|
name: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kawaiininja/layouts",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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",
|