@lerianstudio/sindarian-ui 1.0.0-beta.23 → 1.0.0-beta.25

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.
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  export type SidebarContextProps = {
3
3
  isCollapsed: boolean;
4
4
  items: Record<string, boolean>;
5
+ setItems: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
5
6
  getItemCollapsed: (key: string) => boolean;
6
7
  setItemCollapsed: (key: string, value: boolean) => void;
7
8
  toggleSidebar: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-provider.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/sidebar/sidebar-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IAC1C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACvD,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAMD,eAAO,MAAM,UAAU,2BAMtB,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,cAAc,KAAK,CAAC,iBAAiB,4CAoDpE,CAAA"}
1
+ {"version":3,"file":"sidebar-provider.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/sidebar/sidebar-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACvE,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IAC1C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACvD,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAMD,eAAO,MAAM,UAAU,2BAMtB,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,cAAc,KAAK,CAAC,iBAAiB,4CAqDpE,CAAA"}
@@ -50,6 +50,7 @@ const SidebarProvider = ({ children }) => {
50
50
  return ((0, jsx_runtime_1.jsx)(SidebarContext.Provider, { value: {
51
51
  isCollapsed: collapsed,
52
52
  items,
53
+ setItems: _setItems,
53
54
  getItemCollapsed,
54
55
  setItemCollapsed,
55
56
  toggleSidebar
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sidebar-provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar-provider.test.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/sidebar/sidebar-provider.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const react_1 = require("@testing-library/react");
5
+ const sidebar_provider_1 = require("./sidebar-provider");
6
+ const wrapper = ({ children }) => ((0, jsx_runtime_1.jsx)(sidebar_provider_1.SidebarProvider, { children: children }));
7
+ describe('SidebarProvider', () => {
8
+ beforeEach(() => {
9
+ localStorage.clear();
10
+ jest.clearAllMocks();
11
+ });
12
+ describe('initial state', () => {
13
+ it('should initialize with collapsed as false (SSR-safe default)', () => {
14
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
15
+ expect(result.current.isCollapsed).toBe(false);
16
+ });
17
+ it('should initialize with empty items (SSR-safe default)', () => {
18
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
19
+ expect(result.current.items).toEqual({});
20
+ });
21
+ });
22
+ describe('hydration from localStorage', () => {
23
+ it('should load collapsed state from localStorage after hydration', async () => {
24
+ localStorage.setItem('sidebar-collapsed', 'true');
25
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
26
+ await (0, react_1.waitFor)(() => {
27
+ expect(result.current.isCollapsed).toBe(true);
28
+ });
29
+ });
30
+ it('should load items from localStorage after hydration', async () => {
31
+ const storedItems = { 'item-1': true, 'item-2': false };
32
+ localStorage.setItem('sidebar-items', JSON.stringify(storedItems));
33
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
34
+ await (0, react_1.waitFor)(() => {
35
+ expect(result.current.items).toEqual(storedItems);
36
+ });
37
+ });
38
+ it('should handle invalid JSON in localStorage gracefully', async () => {
39
+ localStorage.setItem('sidebar-items', 'invalid-json');
40
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
41
+ await (0, react_1.waitFor)(() => {
42
+ expect(result.current.items).toEqual({});
43
+ });
44
+ });
45
+ });
46
+ describe('toggleSidebar', () => {
47
+ it('should toggle collapsed state from false to true', async () => {
48
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
49
+ expect(result.current.isCollapsed).toBe(false);
50
+ (0, react_1.act)(() => {
51
+ result.current.toggleSidebar();
52
+ });
53
+ expect(result.current.isCollapsed).toBe(true);
54
+ });
55
+ it('should toggle collapsed state from true to false', async () => {
56
+ localStorage.setItem('sidebar-collapsed', 'true');
57
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
58
+ await (0, react_1.waitFor)(() => {
59
+ expect(result.current.isCollapsed).toBe(true);
60
+ });
61
+ (0, react_1.act)(() => {
62
+ result.current.toggleSidebar();
63
+ });
64
+ expect(result.current.isCollapsed).toBe(false);
65
+ });
66
+ });
67
+ describe('getItemCollapsed', () => {
68
+ it('should return false for non-existent item', () => {
69
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
70
+ expect(result.current.getItemCollapsed('non-existent')).toBe(false);
71
+ });
72
+ it('should return the correct value for existing item', async () => {
73
+ localStorage.setItem('sidebar-items', JSON.stringify({ 'my-item': true }));
74
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
75
+ await (0, react_1.waitFor)(() => {
76
+ expect(result.current.getItemCollapsed('my-item')).toBe(true);
77
+ });
78
+ });
79
+ });
80
+ describe('setItemCollapsed', () => {
81
+ it('should set item collapsed state', () => {
82
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
83
+ (0, react_1.act)(() => {
84
+ result.current.setItemCollapsed('new-item', true);
85
+ });
86
+ expect(result.current.items['new-item']).toBe(true);
87
+ expect(result.current.getItemCollapsed('new-item')).toBe(true);
88
+ });
89
+ it('should update existing item collapsed state', async () => {
90
+ localStorage.setItem('sidebar-items', JSON.stringify({ 'existing-item': true }));
91
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
92
+ await (0, react_1.waitFor)(() => {
93
+ expect(result.current.getItemCollapsed('existing-item')).toBe(true);
94
+ });
95
+ (0, react_1.act)(() => {
96
+ result.current.setItemCollapsed('existing-item', false);
97
+ });
98
+ expect(result.current.getItemCollapsed('existing-item')).toBe(false);
99
+ });
100
+ it('should preserve other items when setting a new item', async () => {
101
+ localStorage.setItem('sidebar-items', JSON.stringify({ 'item-1': true, 'item-2': false }));
102
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
103
+ await (0, react_1.waitFor)(() => {
104
+ expect(result.current.items).toEqual({ 'item-1': true, 'item-2': false });
105
+ });
106
+ (0, react_1.act)(() => {
107
+ result.current.setItemCollapsed('item-3', true);
108
+ });
109
+ expect(result.current.items).toEqual({
110
+ 'item-1': true,
111
+ 'item-2': false,
112
+ 'item-3': true
113
+ });
114
+ });
115
+ });
116
+ describe('localStorage persistence', () => {
117
+ it('should persist collapsed state to localStorage after change', async () => {
118
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
119
+ // Wait for hydration
120
+ await (0, react_1.waitFor)(() => {
121
+ expect(localStorage.getItem('sidebar-collapsed')).toBeDefined();
122
+ });
123
+ (0, react_1.act)(() => {
124
+ result.current.toggleSidebar();
125
+ });
126
+ await (0, react_1.waitFor)(() => {
127
+ expect(localStorage.getItem('sidebar-collapsed')).toBe('true');
128
+ });
129
+ });
130
+ it('should persist items to localStorage after change', async () => {
131
+ const { result } = (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
132
+ // Wait for hydration
133
+ await (0, react_1.waitFor)(() => {
134
+ expect(localStorage.getItem('sidebar-items')).toBeDefined();
135
+ });
136
+ (0, react_1.act)(() => {
137
+ result.current.setItemCollapsed('persisted-item', true);
138
+ });
139
+ await (0, react_1.waitFor)(() => {
140
+ const stored = JSON.parse(localStorage.getItem('sidebar-items') || '{}');
141
+ expect(stored['persisted-item']).toBe(true);
142
+ });
143
+ });
144
+ it('should not overwrite localStorage before hydration completes', async () => {
145
+ const initialItems = { 'pre-existing': true };
146
+ localStorage.setItem('sidebar-items', JSON.stringify(initialItems));
147
+ (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)(), { wrapper });
148
+ // The initial localStorage value should be preserved and loaded
149
+ await (0, react_1.waitFor)(() => {
150
+ const stored = JSON.parse(localStorage.getItem('sidebar-items') || '{}');
151
+ expect(stored['pre-existing']).toBe(true);
152
+ });
153
+ });
154
+ });
155
+ describe('useSidebar hook', () => {
156
+ it('should throw error when used outside SidebarProvider', () => {
157
+ // Suppress console.error for this test
158
+ const consoleSpy = jest
159
+ .spyOn(console, 'error')
160
+ .mockImplementation(() => { });
161
+ expect(() => {
162
+ (0, react_1.renderHook)(() => (0, sidebar_provider_1.useSidebar)());
163
+ }).toThrow('useSidebar must be used within a SidebarProvider');
164
+ consoleSpy.mockRestore();
165
+ });
166
+ });
167
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerianstudio/sindarian-ui",
3
- "version": "1.0.0-beta.23",
3
+ "version": "1.0.0-beta.25",
4
4
  "description": "Sindarian UI - A UI library for Midaz Console",
5
5
  "license": "ISC",
6
6
  "author": {