@startupjs-ui/smart-sidebar 0.1.3

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/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [0.1.3](https://github.com/startupjs/startupjs-ui/compare/v0.1.2...v0.1.3) (2025-12-29)
7
+
8
+ **Note:** Version bump only for package @startupjs-ui/smart-sidebar
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.1.2](https://github.com/startupjs/startupjs-ui/compare/v0.1.1...v0.1.2) (2025-12-29)
15
+
16
+
17
+ ### Features
18
+
19
+ * add mdx and docs packages. Refactor docs to get rid of any @startupjs/ui usage and use startupjs-ui instead ([703c926](https://github.com/startupjs/startupjs-ui/commit/703c92636efb0421ffd11783f692fc892b74018f))
20
+ * **smart-sidebar:** refactor SmartSidebar component ([3ac7b79](https://github.com/startupjs/startupjs-ui/commit/3ac7b79386491a166e4d15577a784d52996fe7d2))
package/README.mdx ADDED
@@ -0,0 +1,270 @@
1
+ import SmartSidebar, { _PropsJsonSchema as SmartSidebarPropsJsonSchema } from './index'
2
+ import Div from '@startupjs-ui/div'
3
+ import Menu from '@startupjs-ui/menu'
4
+ import Button from '@startupjs-ui/button'
5
+ import Br from '@startupjs-ui/br'
6
+ import Content from '@startupjs-ui/content'
7
+ import Span from '@startupjs-ui/span'
8
+ import { pug, $ } from 'startupjs'
9
+ import { Sandbox } from '@startupjs-ui/docs'
10
+ import './index.mdx.cssx.styl'
11
+
12
+ # SmartSidebar
13
+
14
+ SmartSidebar is typically used for navigation. It provides a desktop-mobile friendly interface. Based on a fixed layout breakpoint, it decides to stay as a [sidebar](/docs/components/Sidebar) or to turn into an [drawer sidebar](/docs/components/DrawerSidebar). By default it not visible on the screen.
15
+
16
+ ```jsx
17
+ import { SmartSidebar } from 'startupjs-ui'
18
+ ```
19
+
20
+ ## Simple Example
21
+
22
+ ```jsx example
23
+ const $open = $()
24
+
25
+ return (
26
+ <Div style={{overflow: 'hidden'}}>
27
+ <SmartSidebar
28
+ $open={$open}
29
+ renderContent={() => (
30
+ <Span>SmartSidebar</Span>
31
+ )}
32
+ >
33
+ <Button onPress={() => $open.set(!$open.get())}>Toggle Sidebar</Button>
34
+ </SmartSidebar>
35
+ </Div>
36
+ )
37
+ ```
38
+
39
+ ## Fixed Layout Breakpoint
40
+
41
+ The `fixedLayoutBreakpoint` property specifies the screen width breakpoint below which the [sidebar](/docs/components/Sidebar) switches to a [drawer sidebar](/docs/components/DrawerSidebar). `fixedLayoutBreakpoint` is a number type with a default value of `1024`.
42
+
43
+ ```jsx example noscroll
44
+ const $open = $()
45
+ return (
46
+ <Div style={{overflow: 'hidden'}}>
47
+ <SmartSidebar
48
+ $open={$open}
49
+ renderContent={() => (
50
+ <Menu>
51
+ <Menu.Item onPress={() => null}>Nav-1</Menu.Item>
52
+ <Menu.Item onPress={() => null}>Nav-2</Menu.Item>
53
+ <Menu.Item onPress={() => null}>Nav-3</Menu.Item>
54
+ </Menu>
55
+ )}
56
+ fixedLayoutBreakpoint={10000}
57
+ >
58
+ <Content
59
+ padding
60
+ width='full'
61
+ style={{ backgroundColor: 'white' }}
62
+ >
63
+ <Div row>
64
+ <Button onPress={() => $open.set(!$open.get())}>Toggle</Button>
65
+ </Div>
66
+ <Br />
67
+ <Span>
68
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit gravida rutrum quisque non tellus.
69
+ </Span>
70
+ </Content>
71
+ </SmartSidebar>
72
+ </Div>
73
+ )
74
+ ```
75
+
76
+ ## Position
77
+
78
+ The `position` property specifies the side of the window from which the sidebar will show. Possible values of `position` property are `left` (default) and `right`.
79
+
80
+ ```jsx example noscroll
81
+ const $open = $()
82
+ return (
83
+ <Div style={{overflow: 'hidden'}}>
84
+ <SmartSidebar
85
+ $open={$open}
86
+ renderContent={() => (
87
+ <Div>
88
+ <Br />
89
+ <Menu>
90
+ <Menu.Item onPress={() => null}>Nav-1</Menu.Item>
91
+ <Menu.Item onPress={() => null}>Nav-2</Menu.Item>
92
+ <Menu.Item onPress={() => null}>Nav-3</Menu.Item>
93
+ </Menu>
94
+ </Div>
95
+ )}
96
+ position={'right'}
97
+ >
98
+ <Content
99
+ padding
100
+ width='full'
101
+ style={{ backgroundColor: 'white' }}
102
+ >
103
+ <Div row>
104
+ <Button onPress={() => $open.set(!$open.get())}>Toggle right sidebar</Button>
105
+ </Div>
106
+ <Br />
107
+ <Span>
108
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit gravida rutrum quisque non tellus.
109
+ </Span>
110
+ </Content>
111
+ </SmartSidebar>
112
+ </Div>
113
+ )
114
+ ```
115
+
116
+ ## Default visibility (desktop only)
117
+
118
+ To control default visibility use `defaultOpen` property.
119
+
120
+ ```jsx example
121
+ const $open = $()
122
+ return (
123
+ <Div style={{overflow: 'hidden'}}>
124
+ <SmartSidebar
125
+ $open={$open}
126
+ renderContent={() => (
127
+ <Div>
128
+ <Br />
129
+ <Menu>
130
+ <Menu.Item onPress={() => null}>Nav-1</Menu.Item>
131
+ <Menu.Item onPress={() => null}>Nav-2</Menu.Item>
132
+ <Menu.Item onPress={() => null}>Nav-3</Menu.Item>
133
+ </Menu>
134
+ </Div>
135
+ )}
136
+ defaultOpen
137
+ >
138
+ <Content
139
+ padding
140
+ width='full'
141
+ style={{ backgroundColor: 'white' }}
142
+ >
143
+ <Div row>
144
+ <Button onPress={() => $open.set(!$open.get())}>Toggle</Button>
145
+ </Div>
146
+ </Content>
147
+ </SmartSidebar>
148
+ </Div>
149
+ )
150
+ ```
151
+
152
+ ## Locked SmartSidebar
153
+
154
+ Specifying `disabled` property will keep the sidebar closed and it won't respond to `open` property.
155
+
156
+ ```jsx example
157
+ const $open = $()
158
+ return (
159
+ <Div style={{overflow: 'hidden'}}>
160
+ <SmartSidebar
161
+ $open={$open}
162
+ renderContent={() => (
163
+ <Div>
164
+ <Br />
165
+ <Menu>
166
+ <Menu.Item onPress={() => null}>Nav-1</Menu.Item>
167
+ <Menu.Item onPress={() => null}>Nav-2</Menu.Item>
168
+ <Menu.Item onPress={() => null}>Nav-3</Menu.Item>
169
+ </Menu>
170
+ </Div>
171
+ )}
172
+ disabled
173
+ >
174
+ <Content
175
+ padding
176
+ width='full'
177
+ style={{ backgroundColor: 'white' }}
178
+ >
179
+ <Div row>
180
+ <Button onPress={() => $open.set(!$open.get())}>Toggle</Button>
181
+ </Div>
182
+ </Content>
183
+ </SmartSidebar>
184
+ </Div>
185
+ )
186
+ ```
187
+
188
+ ## Lazy rendering
189
+
190
+ By default the smart sidebar content are not destroyed when it is closed. To change this behavior pass `lazy=true`.
191
+
192
+ ```jsx example
193
+ const $open = $()
194
+
195
+ return (
196
+ <Div style={{overflow: 'hidden'}}>
197
+ <SmartSidebar
198
+ $open={$open}
199
+ renderContent={() => (
200
+ <Span>Lazy SmartSidebar</Span>
201
+ )}
202
+ lazy
203
+ >
204
+ <Button onPress={() => $open.set(!$open.get())}>Toggle Sidebar</Button>
205
+ </SmartSidebar>
206
+ </Div>
207
+ )
208
+ ```
209
+
210
+ ## Complex example
211
+
212
+ ```jsx example noscroll
213
+ const $open = $()
214
+ return (
215
+ <Div style={{overflow: 'hidden'}}>
216
+ <SmartSidebar
217
+ $open={$open}
218
+ renderContent={() => (
219
+ <Menu>
220
+ <Menu.Item onPress={() => null}>Nav-1</Menu.Item>
221
+ <Menu.Item onPress={() => null}>Nav-2</Menu.Item>
222
+ <Menu.Item onPress={() => null}>Nav-3</Menu.Item>
223
+ </Menu>
224
+ )}
225
+ >
226
+ <Content
227
+ padding
228
+ width='full'
229
+ style={{ backgroundColor: 'white' }}
230
+ >
231
+ <Div row>
232
+ <Button onPress={() => $open.set(!$open.get())}>Toggle</Button>
233
+ </Div>
234
+ <Br />
235
+ <Span>
236
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit gravida rutrum quisque non tellus.
237
+ </Span>
238
+ </Content>
239
+ </SmartSidebar>
240
+ </Div>
241
+ )
242
+ ```
243
+
244
+ ## Sandbox
245
+
246
+ <Sandbox Component={SmartSidebar}
247
+ props={{
248
+ $open: $.session.Sandbox.SmartSidebar,
249
+ renderContent: () => {
250
+ return pug`
251
+ Div.sidebar
252
+ Span Sidebar content
253
+ `
254
+ },
255
+ children: pug`
256
+ Div.content
257
+ Button.button(
258
+ onPress=() => {
259
+ const value = $.session.Sandbox.SmartSidebar.get()
260
+ $.session.Sandbox.SmartSidebar.set(!value)
261
+ }
262
+ ) Toggle
263
+ Br
264
+ Span Children content
265
+ `
266
+ }}
267
+ propsJsonSchema={SmartSidebarPropsJsonSchema}
268
+ rendererStyleName='renderer'
269
+ block
270
+ />
package/index.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /* eslint-disable */
2
+ // DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
3
+
4
+ import React, { type ReactNode } from 'react';
5
+ import { type StyleProp, type ViewStyle } from 'react-native';
6
+ export declare const _PropsJsonSchema: {};
7
+ export interface SmartSidebarProps {
8
+ /** Custom styles applied to the root wrapper */
9
+ style?: StyleProp<ViewStyle>;
10
+ /** Custom styles applied to the sidebar container when using fixed layout */
11
+ sidebarStyle?: StyleProp<ViewStyle>;
12
+ /** Model controlling sidebar open state */
13
+ $open?: any;
14
+ /** Open sidebar by default on desktop @default false */
15
+ defaultOpen?: boolean;
16
+ /** Destroy sidebar content when closed @default false */
17
+ lazy?: boolean;
18
+ /** Disable sidebar interactions @default false */
19
+ disabled?: boolean;
20
+ /** Breakpoint width after which sidebar switches to fixed layout @default 1024 */
21
+ fixedLayoutBreakpoint?: number;
22
+ /** Sidebar position relative to the screen @default 'left' */
23
+ position?: 'left' | 'right';
24
+ /** Sidebar width in density-independent pixels @default 264 */
25
+ width?: number;
26
+ /** Content rendered inside the main area */
27
+ children?: ReactNode;
28
+ /** Renderer for sidebar content */
29
+ renderContent?: () => ReactNode;
30
+ }
31
+ declare const _default: React.ComponentType<SmartSidebarProps>;
32
+ export default _default;
@@ -0,0 +1,14 @@
1
+ .sidebar
2
+ padding 2u
3
+ height 20u
4
+
5
+ .content
6
+ padding 2u
7
+ height 20u
8
+ background-color var(--color-bg-main)
9
+
10
+ .button
11
+ width 10u
12
+
13
+ .renderer
14
+ overflow hidden
package/index.tsx ADDED
@@ -0,0 +1,127 @@
1
+ import React, { useEffect, type ReactNode } from 'react'
2
+ import { Dimensions, type StyleProp, type ViewStyle } from 'react-native'
3
+ import { pug, observer, $, useBind } from 'startupjs'
4
+ import { themed } from '@startupjs-ui/core'
5
+ import Sidebar from '@startupjs-ui/sidebar'
6
+ import DrawerSidebar from '@startupjs-ui/drawer-sidebar'
7
+
8
+ const FIXED_LAYOUT_BREAKPOINT = 1024
9
+
10
+ export const _PropsJsonSchema = {/* SmartSidebarProps */}
11
+
12
+ export interface SmartSidebarProps {
13
+ /** Custom styles applied to the root wrapper */
14
+ style?: StyleProp<ViewStyle>
15
+ /** Custom styles applied to the sidebar container when using fixed layout */
16
+ sidebarStyle?: StyleProp<ViewStyle>
17
+ /** Model controlling sidebar open state */
18
+ $open?: any
19
+ /** Open sidebar by default on desktop @default false */
20
+ defaultOpen?: boolean
21
+ /** Destroy sidebar content when closed @default false */
22
+ lazy?: boolean
23
+ /** Disable sidebar interactions @default false */
24
+ disabled?: boolean
25
+ /** Breakpoint width after which sidebar switches to fixed layout @default 1024 */
26
+ fixedLayoutBreakpoint?: number
27
+ /** Sidebar position relative to the screen @default 'left' */
28
+ position?: 'left' | 'right'
29
+ /** Sidebar width in density-independent pixels @default 264 */
30
+ width?: number
31
+ /** Content rendered inside the main area */
32
+ children?: ReactNode
33
+ /** Renderer for sidebar content */
34
+ renderContent?: () => ReactNode
35
+ }
36
+
37
+ function SmartSidebar ({
38
+ style,
39
+ sidebarStyle,
40
+ defaultOpen = false,
41
+ lazy = false,
42
+ disabled = false,
43
+ fixedLayoutBreakpoint = FIXED_LAYOUT_BREAKPOINT,
44
+ $open,
45
+ position = 'left',
46
+ width = 264,
47
+ children,
48
+ renderContent,
49
+ ...props
50
+ }: SmartSidebarProps): ReactNode {
51
+ if (!$open) $open = $()
52
+
53
+ let open: boolean | undefined
54
+ let onChange: ((value: boolean) => void) | undefined
55
+ ;({ open, onChange } = useBind({ $open, open, onChange }) as any) // eslint-disable-line prefer-const
56
+
57
+ const $fixedLayout = $(isFixedLayout(fixedLayoutBreakpoint))
58
+ const fixedLayout = $fixedLayout.get()
59
+
60
+ /* eslint-disable react-hooks/exhaustive-deps */
61
+ useEffect(() => {
62
+ if (!$fixedLayout.get()) return
63
+ // or we can save open state before disabling
64
+ // to open it with this state when enabling
65
+ $open.set(defaultOpen)
66
+ }, [disabled])
67
+
68
+ useEffect(() => {
69
+ if (disabled) return
70
+ if ($fixedLayout.get()) {
71
+ // when change dimensions from mobile
72
+ // to desktop resolution or when rendering happen on desktop resolution
73
+ // we open sidebar if it was opened on mobile resolution or default value
74
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
75
+ $open.set(open || defaultOpen)
76
+ } else {
77
+ // when change dimensions from desktop
78
+ // to mobile resolution or when rendering heppen for mobile resolution
79
+ // we always close sidebars
80
+ $open.set(false)
81
+ }
82
+ }, [$fixedLayout.get()])
83
+
84
+ useEffect(() => {
85
+ const subscription = Dimensions.addEventListener('change', handleWidthChange)
86
+
87
+ return () => {
88
+ subscription?.remove()
89
+ }
90
+ }, [])
91
+ /* eslint-enable react-hooks/exhaustive-deps */
92
+
93
+ function handleWidthChange () {
94
+ $fixedLayout.set(isFixedLayout(fixedLayoutBreakpoint))
95
+ }
96
+
97
+ return pug`
98
+ if fixedLayout
99
+ Sidebar(
100
+ style=style
101
+ sidebarStyle=sidebarStyle
102
+ $open=$open
103
+ position=position
104
+ width=width
105
+ disabled=disabled
106
+ renderContent=renderContent
107
+ ...props
108
+ )= children
109
+ else
110
+ DrawerSidebar(
111
+ style=style
112
+ $open=$open
113
+ position=position
114
+ width=width
115
+ renderContent=renderContent
116
+ disabled=disabled
117
+ ...props
118
+ )= children
119
+ `
120
+ }
121
+
122
+ export default observer(themed('SmartSidebar', SmartSidebar))
123
+
124
+ function isFixedLayout (fixedLayoutBreakpoint: number) {
125
+ const dim = Dimensions.get('window')
126
+ return dim.width > fixedLayoutBreakpoint
127
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@startupjs-ui/smart-sidebar",
3
+ "version": "0.1.3",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "main": "index.tsx",
8
+ "types": "index.d.ts",
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@startupjs-ui/core": "^0.1.3",
12
+ "@startupjs-ui/drawer-sidebar": "^0.1.3",
13
+ "@startupjs-ui/sidebar": "^0.1.3"
14
+ },
15
+ "peerDependencies": {
16
+ "react": "*",
17
+ "react-native": "*",
18
+ "startupjs": "*"
19
+ },
20
+ "gitHead": "fd964ebc3892d3dd0a6c85438c0af619cc50c3f0"
21
+ }