@robosophy/ui-react 3.0.0 → 4.0.1
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/AGENTS.md +17 -5
- package/README.md +23 -9
- package/dist/{chunk-DA5JOU36.js → chunk-H3GFVSAQ.js} +38 -22
- package/dist/components/RsSidebar/index.css +13 -9
- package/dist/components/RsSidebar/index.d.ts +4 -0
- package/dist/components/RsSidebar/index.js +1 -1
- package/dist/index.css +13 -9
- package/dist/index.js +1 -1
- package/package.json +11 -8
package/AGENTS.md
CHANGED
|
@@ -27,23 +27,35 @@ The main barrel (`@robosophy/ui-react`) loads all components including PrimeReac
|
|
|
27
27
|
|
|
28
28
|
## CSS Imports
|
|
29
29
|
|
|
30
|
-
PrimeReact apps:
|
|
30
|
+
PrimeReact apps: the consuming app owns the layer order. Put the base theme in `prime-base` and import the Robosophy overrides afterward:
|
|
31
|
+
|
|
32
|
+
Crea un archivo `layers.css` en tu aplicación:
|
|
33
|
+
|
|
34
|
+
```css
|
|
35
|
+
/* layers.css */
|
|
36
|
+
@layer prime-base, prime-design;
|
|
37
|
+
@import "primereact/resources/themes/fluent-light/theme.css" layer(prime-base);
|
|
38
|
+
@import "@robosophy/prime-theme/prime.css" layer(prime-design);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Luego importa este archivo en tu aplicación:
|
|
31
42
|
|
|
32
43
|
```tsx
|
|
33
|
-
import { PrimeReactProvider } from "
|
|
34
|
-
import
|
|
35
|
-
import "@robosophy/prime-theme/prime.css";
|
|
44
|
+
import { PrimeReactProvider } from "primereact/api";
|
|
45
|
+
import "./layers.css";
|
|
36
46
|
import "@robosophy/ui-react/styles.css";
|
|
37
47
|
|
|
38
48
|
function MyApp({ Component, pageProps }) {
|
|
39
49
|
return (
|
|
40
|
-
<PrimeReactProvider
|
|
50
|
+
<PrimeReactProvider>
|
|
41
51
|
<Component {...pageProps} />
|
|
42
52
|
</PrimeReactProvider>
|
|
43
53
|
);
|
|
44
54
|
}
|
|
45
55
|
```
|
|
46
56
|
|
|
57
|
+
The consuming app establishes the order: PrimeReact's base theme first, Robosophy overrides in `prime-design` next, and app styles without a layer last so they can override both.
|
|
58
|
+
|
|
47
59
|
Non-PrimeReact apps:
|
|
48
60
|
|
|
49
61
|
```tsx
|
package/README.md
CHANGED
|
@@ -28,25 +28,39 @@ npm install @robosophy/ui-react @robosophy/tokens react react-dom
|
|
|
28
28
|
|
|
29
29
|
## PrimeReact theme
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
PrimeReact 10 usa un sistema de temas CSS. La app consumidora define el orden de layers: el tema `fluent-light` en `prime-base` y los overrides de Robosophy en `prime-design`.
|
|
32
|
+
|
|
33
|
+
En el CSS de la app:
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
/* app/layers.css */
|
|
37
|
+
@layer prime-base, prime-design;
|
|
38
|
+
@import "primereact/resources/themes/fluent-light/theme.css" layer(prime-base);
|
|
39
|
+
@import "@robosophy/prime-theme/prime.css" layer(prime-design);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Luego importa ese CSS en la app junto con los estilos de UI React:
|
|
32
43
|
|
|
33
44
|
```tsx
|
|
34
|
-
// app/layout.tsx
|
|
35
|
-
import { PrimeReactProvider } from "
|
|
36
|
-
import
|
|
37
|
-
import "@robosophy/prime-theme/prime.css";
|
|
45
|
+
// app/layout.tsx o pages/_app.tsx
|
|
46
|
+
import { PrimeReactProvider } from "primereact/api";
|
|
47
|
+
import "./layers.css";
|
|
38
48
|
import "@robosophy/ui-react/styles.css";
|
|
39
49
|
|
|
40
50
|
function MyApp({ Component, pageProps }) {
|
|
41
51
|
return (
|
|
42
|
-
<PrimeReactProvider
|
|
52
|
+
<PrimeReactProvider>
|
|
43
53
|
<Component {...pageProps} />
|
|
44
54
|
</PrimeReactProvider>
|
|
45
55
|
);
|
|
46
56
|
}
|
|
47
57
|
```
|
|
48
58
|
|
|
49
|
-
`prime.css`
|
|
59
|
+
El tema base de PrimeReact queda en la layer inferior; `prime.css` aporta overrides en `prime-design`. Los estilos propios de la app, sin layer, pueden sobrescribir ambas capas.
|
|
60
|
+
|
|
61
|
+
`prime.css` ya importa `@robosophy/tokens/tokens.css`, así que no dupliques ese import.
|
|
62
|
+
|
|
63
|
+
Solo `fluent-light` es compatible con los overrides de Robosophy.
|
|
50
64
|
|
|
51
65
|
If your app doesn't use PrimeReact, import tokens once:
|
|
52
66
|
|
|
@@ -148,7 +162,7 @@ robosophyMaterialSymbols({
|
|
|
148
162
|
For PrimeReact APIs that receive `icon` as a string, use the helper:
|
|
149
163
|
|
|
150
164
|
```tsx
|
|
151
|
-
import { Button } from "
|
|
165
|
+
import { Button } from "primereact/button";
|
|
152
166
|
import { rsPrimeIcon } from "@robosophy/ui-react";
|
|
153
167
|
|
|
154
168
|
<Button label="Inicio" icon={rsPrimeIcon("home")} />
|
|
@@ -158,7 +172,7 @@ import { rsPrimeIcon } from "@robosophy/ui-react";
|
|
|
158
172
|
For full control over props (fill, grade, etc.), use the `icon` slot:
|
|
159
173
|
|
|
160
174
|
```tsx
|
|
161
|
-
import { Button } from "
|
|
175
|
+
import { Button } from "primereact/button";
|
|
162
176
|
import { RsIcon } from "@robosophy/ui-react";
|
|
163
177
|
|
|
164
178
|
<Button label="Favorito" icon={<RsIcon name="favorite" fill color="danger" />} />
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
|
|
5
5
|
// src/components/RsSidebar/RsSidebar.tsx
|
|
6
6
|
import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
-
import { Menu } from "
|
|
7
|
+
import { Menu } from "primereact/menu";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
var variantIconMap = {
|
|
10
10
|
pc: "article",
|
|
@@ -44,7 +44,9 @@ var RsSidebar = forwardRef(
|
|
|
44
44
|
const [isHovered, setIsHovered] = useState(false);
|
|
45
45
|
const [activeParent, setActiveParent] = useState(null);
|
|
46
46
|
const [isModuleMenuOpen, setIsModuleMenuOpen] = useState(false);
|
|
47
|
+
const [menuTop, setMenuTop] = useState(88);
|
|
47
48
|
const rootRef = useRef(null);
|
|
49
|
+
const headerRef = useRef(null);
|
|
48
50
|
const isFirstRenderRef = useRef(true);
|
|
49
51
|
const onExpandedChangeRef = useRef(onExpandedChange);
|
|
50
52
|
onExpandedChangeRef.current = onExpandedChange;
|
|
@@ -77,11 +79,30 @@ var RsSidebar = forwardRef(
|
|
|
77
79
|
setIsModuleMenuOpen(false);
|
|
78
80
|
onModuleSelect?.(module);
|
|
79
81
|
if (navigateOnModuleSelect && typeof window !== "undefined" && module.link) {
|
|
82
|
+
console.warn(
|
|
83
|
+
"[RsSidebar] navigateOnModuleSelect is deprecated. Use onModuleSelect and handle navigation in your app to avoid full page reloads in SPAs."
|
|
84
|
+
);
|
|
80
85
|
window.location.href = module.link;
|
|
81
86
|
}
|
|
82
87
|
},
|
|
83
88
|
[navigateOnModuleSelect, onModuleSelect]
|
|
84
89
|
);
|
|
90
|
+
const moduleMenuItems = useMemo(
|
|
91
|
+
() => modules.map((module) => {
|
|
92
|
+
const isCurrent = module.active || module.text === displayedHeaderTitle;
|
|
93
|
+
return {
|
|
94
|
+
className: [
|
|
95
|
+
"rs-sidebar__module-option",
|
|
96
|
+
isCurrent ? "rs-sidebar__module-option--active" : "",
|
|
97
|
+
module.disabled || isCurrent ? "rs-sidebar__module-option--disabled" : ""
|
|
98
|
+
].filter(Boolean).join(" "),
|
|
99
|
+
command: () => selectModule(module),
|
|
100
|
+
disabled: module.disabled || isCurrent,
|
|
101
|
+
label: module.text
|
|
102
|
+
};
|
|
103
|
+
}),
|
|
104
|
+
[modules, displayedHeaderTitle, selectModule]
|
|
105
|
+
);
|
|
85
106
|
const displayedItems = useMemo(
|
|
86
107
|
() => activeParent ? (activeParent.children ?? []).filter(isVisible) : visibleItems,
|
|
87
108
|
[activeParent, visibleItems]
|
|
@@ -106,6 +127,11 @@ var RsSidebar = forwardRef(
|
|
|
106
127
|
}
|
|
107
128
|
return classes.join(" ");
|
|
108
129
|
}, [variant, isExpanded, mobileOpen, activeParent]);
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (headerRef.current) {
|
|
132
|
+
setMenuTop(headerRef.current.offsetHeight);
|
|
133
|
+
}
|
|
134
|
+
}, [isExpanded, mobileOpen]);
|
|
109
135
|
useEffect(() => {
|
|
110
136
|
if (!mobileOpen) {
|
|
111
137
|
setActiveParent(null);
|
|
@@ -196,7 +222,7 @@ var RsSidebar = forwardRef(
|
|
|
196
222
|
if (header) {
|
|
197
223
|
return header;
|
|
198
224
|
}
|
|
199
|
-
return /* @__PURE__ */ jsxs("header", { className: "rs-sidebar__header", children: [
|
|
225
|
+
return /* @__PURE__ */ jsxs("header", { ref: headerRef, className: "rs-sidebar__header", children: [
|
|
200
226
|
/* @__PURE__ */ jsx(
|
|
201
227
|
"div",
|
|
202
228
|
{
|
|
@@ -232,7 +258,8 @@ var RsSidebar = forwardRef(
|
|
|
232
258
|
] })
|
|
233
259
|
}
|
|
234
260
|
),
|
|
235
|
-
renderHeaderAction()
|
|
261
|
+
renderHeaderAction(),
|
|
262
|
+
renderModuleMenu()
|
|
236
263
|
] });
|
|
237
264
|
};
|
|
238
265
|
const renderHeaderAction = () => {
|
|
@@ -265,24 +292,14 @@ var RsSidebar = forwardRef(
|
|
|
265
292
|
if (!hasModuleSelector || !isModuleMenuOpen) {
|
|
266
293
|
return null;
|
|
267
294
|
}
|
|
268
|
-
return /* @__PURE__ */ jsx(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
{
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
isCurrent ? "rs-sidebar__module-option--active" : "",
|
|
277
|
-
module.disabled || isCurrent ? "rs-sidebar__module-option--disabled" : ""
|
|
278
|
-
].filter(Boolean).join(" "),
|
|
279
|
-
disabled: module.disabled || isCurrent,
|
|
280
|
-
onSelect: () => selectModule(module),
|
|
281
|
-
children: module.text
|
|
282
|
-
},
|
|
283
|
-
module.text
|
|
284
|
-
);
|
|
285
|
-
}) }) });
|
|
295
|
+
return /* @__PURE__ */ jsx(
|
|
296
|
+
Menu,
|
|
297
|
+
{
|
|
298
|
+
className: "rs-sidebar__module-menu",
|
|
299
|
+
style: { "--rs-sidebar-menu-top": `${menuTop}px` },
|
|
300
|
+
model: moduleMenuItems
|
|
301
|
+
}
|
|
302
|
+
);
|
|
286
303
|
};
|
|
287
304
|
const renderFooterContent = () => {
|
|
288
305
|
if (typeof footer === "function") {
|
|
@@ -327,7 +344,6 @@ var RsSidebar = forwardRef(
|
|
|
327
344
|
onMouseLeave: () => setHovered(false),
|
|
328
345
|
children: [
|
|
329
346
|
renderHeaderContent(),
|
|
330
|
-
renderModuleMenu(),
|
|
331
347
|
/* @__PURE__ */ jsxs("div", { className: "rs-sidebar__content", children: [
|
|
332
348
|
/* @__PURE__ */ jsx("nav", { className: "rs-sidebar__nav", "aria-label": "Secciones", children: /* @__PURE__ */ jsxs("ul", { className: "rs-sidebar__list", children: [
|
|
333
349
|
activeParent && /* @__PURE__ */ jsx("li", { className: "rs-sidebar__list-item", children: /* @__PURE__ */ jsxs(
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
line-height: 1;
|
|
133
133
|
text-overflow: ellipsis;
|
|
134
134
|
}
|
|
135
|
-
.rs-sidebar__module-menu {
|
|
135
|
+
.rs-sidebar__module-menu.p-menu {
|
|
136
136
|
background: var(--rs-sidebar-background);
|
|
137
137
|
border: 1px solid var(--rs-sidebar-border);
|
|
138
138
|
border-radius: 4px;
|
|
@@ -142,37 +142,41 @@
|
|
|
142
142
|
overflow: hidden;
|
|
143
143
|
padding: 0;
|
|
144
144
|
position: absolute;
|
|
145
|
-
top: 88px;
|
|
145
|
+
top: var(--rs-sidebar-menu-top, 88px);
|
|
146
146
|
z-index: 20;
|
|
147
147
|
}
|
|
148
148
|
.rs-sidebar__module-menu .p-menu-list {
|
|
149
149
|
gap: 0;
|
|
150
150
|
padding: 0;
|
|
151
151
|
}
|
|
152
|
-
.rs-sidebar__module-
|
|
152
|
+
.rs-sidebar__module-option .p-menuitem-content {
|
|
153
153
|
color: var(--rs-sidebar-color);
|
|
154
154
|
border-radius: 0;
|
|
155
|
+
}
|
|
156
|
+
.rs-sidebar__module-option .p-menuitem-link {
|
|
155
157
|
font-family: inherit;
|
|
156
158
|
font-size: inherit;
|
|
157
159
|
line-height: 1;
|
|
158
160
|
min-height: 38px;
|
|
159
161
|
padding: 10px 14px;
|
|
160
162
|
}
|
|
161
|
-
.rs-sidebar__module-
|
|
162
|
-
.rs-sidebar__module-
|
|
163
|
+
.rs-sidebar__module-option:not(.p-disabled) .p-menuitem-content:hover,
|
|
164
|
+
.rs-sidebar__module-option--active .p-menuitem-content {
|
|
163
165
|
background: var(--rs-sidebar-hover);
|
|
164
166
|
color: var(--rs-sidebar-color);
|
|
165
167
|
}
|
|
166
|
-
.rs-sidebar__module-
|
|
168
|
+
.rs-sidebar__module-option--disabled .p-menuitem-content {
|
|
167
169
|
color: var(--rs-sidebar-muted);
|
|
168
170
|
cursor: not-allowed;
|
|
169
171
|
}
|
|
170
|
-
.rs-sidebar__module-
|
|
172
|
+
.rs-sidebar__module-option--disabled .p-menuitem-content:hover {
|
|
171
173
|
background: transparent;
|
|
172
174
|
}
|
|
173
|
-
.rs-sidebar__module-
|
|
175
|
+
.rs-sidebar__module-option.p-focus .p-menuitem-content {
|
|
174
176
|
background: var(--rs-sidebar-hover);
|
|
175
177
|
color: var(--rs-sidebar-color);
|
|
178
|
+
}
|
|
179
|
+
.rs-sidebar__module-option.p-focus .p-menuitem-link {
|
|
176
180
|
outline: 2px solid var(--rs-color-stroke-focused, #48a0d4);
|
|
177
181
|
outline-offset: -2px;
|
|
178
182
|
}
|
|
@@ -294,7 +298,7 @@
|
|
|
294
298
|
.rs-sidebar--mobile-open .rs-sidebar__module-menu {
|
|
295
299
|
left: 16px;
|
|
296
300
|
min-width: min(320px, calc(100% - 32px));
|
|
297
|
-
top: 88px;
|
|
301
|
+
top: var(--rs-sidebar-menu-top, 88px);
|
|
298
302
|
}
|
|
299
303
|
.rs-sidebar--mobile-open .rs-sidebar__item {
|
|
300
304
|
font-size: 18px;
|
|
@@ -22,6 +22,10 @@ type RsSidebarProps = {
|
|
|
22
22
|
items: RsSidebarItem[];
|
|
23
23
|
footerItems?: RsSidebarItem[];
|
|
24
24
|
modules?: RsSidebarModule[];
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use `onModuleSelect` instead and handle navigation in your app.
|
|
27
|
+
* This prop causes a full page reload in SPAs.
|
|
28
|
+
*/
|
|
25
29
|
navigateOnModuleSelect?: boolean;
|
|
26
30
|
title?: string;
|
|
27
31
|
icon?: string;
|
package/dist/index.css
CHANGED
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
line-height: 1;
|
|
183
183
|
text-overflow: ellipsis;
|
|
184
184
|
}
|
|
185
|
-
.rs-sidebar__module-menu {
|
|
185
|
+
.rs-sidebar__module-menu.p-menu {
|
|
186
186
|
background: var(--rs-sidebar-background);
|
|
187
187
|
border: 1px solid var(--rs-sidebar-border);
|
|
188
188
|
border-radius: 4px;
|
|
@@ -192,37 +192,41 @@
|
|
|
192
192
|
overflow: hidden;
|
|
193
193
|
padding: 0;
|
|
194
194
|
position: absolute;
|
|
195
|
-
top: 88px;
|
|
195
|
+
top: var(--rs-sidebar-menu-top, 88px);
|
|
196
196
|
z-index: 20;
|
|
197
197
|
}
|
|
198
198
|
.rs-sidebar__module-menu .p-menu-list {
|
|
199
199
|
gap: 0;
|
|
200
200
|
padding: 0;
|
|
201
201
|
}
|
|
202
|
-
.rs-sidebar__module-
|
|
202
|
+
.rs-sidebar__module-option .p-menuitem-content {
|
|
203
203
|
color: var(--rs-sidebar-color);
|
|
204
204
|
border-radius: 0;
|
|
205
|
+
}
|
|
206
|
+
.rs-sidebar__module-option .p-menuitem-link {
|
|
205
207
|
font-family: inherit;
|
|
206
208
|
font-size: inherit;
|
|
207
209
|
line-height: 1;
|
|
208
210
|
min-height: 38px;
|
|
209
211
|
padding: 10px 14px;
|
|
210
212
|
}
|
|
211
|
-
.rs-sidebar__module-
|
|
212
|
-
.rs-sidebar__module-
|
|
213
|
+
.rs-sidebar__module-option:not(.p-disabled) .p-menuitem-content:hover,
|
|
214
|
+
.rs-sidebar__module-option--active .p-menuitem-content {
|
|
213
215
|
background: var(--rs-sidebar-hover);
|
|
214
216
|
color: var(--rs-sidebar-color);
|
|
215
217
|
}
|
|
216
|
-
.rs-sidebar__module-
|
|
218
|
+
.rs-sidebar__module-option--disabled .p-menuitem-content {
|
|
217
219
|
color: var(--rs-sidebar-muted);
|
|
218
220
|
cursor: not-allowed;
|
|
219
221
|
}
|
|
220
|
-
.rs-sidebar__module-
|
|
222
|
+
.rs-sidebar__module-option--disabled .p-menuitem-content:hover {
|
|
221
223
|
background: transparent;
|
|
222
224
|
}
|
|
223
|
-
.rs-sidebar__module-
|
|
225
|
+
.rs-sidebar__module-option.p-focus .p-menuitem-content {
|
|
224
226
|
background: var(--rs-sidebar-hover);
|
|
225
227
|
color: var(--rs-sidebar-color);
|
|
228
|
+
}
|
|
229
|
+
.rs-sidebar__module-option.p-focus .p-menuitem-link {
|
|
226
230
|
outline: 2px solid var(--rs-color-stroke-focused, #48a0d4);
|
|
227
231
|
outline-offset: -2px;
|
|
228
232
|
}
|
|
@@ -344,7 +348,7 @@
|
|
|
344
348
|
.rs-sidebar--mobile-open .rs-sidebar__module-menu {
|
|
345
349
|
left: 16px;
|
|
346
350
|
min-width: min(320px, calc(100% - 32px));
|
|
347
|
-
top: 88px;
|
|
351
|
+
top: var(--rs-sidebar-menu-top, 88px);
|
|
348
352
|
}
|
|
349
353
|
.rs-sidebar--mobile-open .rs-sidebar__item {
|
|
350
354
|
font-size: 18px;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robosophy/ui-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -43,9 +43,10 @@
|
|
|
43
43
|
"test": "vitest run"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@
|
|
47
|
-
"
|
|
48
|
-
"react
|
|
46
|
+
"@robosophy/prime-theme": ">=3.0.0",
|
|
47
|
+
"primereact": ">=10",
|
|
48
|
+
"react": ">=18",
|
|
49
|
+
"react-dom": ">=18"
|
|
49
50
|
},
|
|
50
51
|
"peerDependenciesMeta": {
|
|
51
52
|
"react": {
|
|
@@ -54,15 +55,17 @@
|
|
|
54
55
|
"react-dom": {
|
|
55
56
|
"optional": true
|
|
56
57
|
},
|
|
57
|
-
"
|
|
58
|
+
"primereact": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"@robosophy/prime-theme": {
|
|
58
62
|
"optional": true
|
|
59
63
|
}
|
|
60
64
|
},
|
|
61
65
|
"dependencies": {
|
|
62
|
-
"@robosophy/tokens": "^1.0
|
|
66
|
+
"@robosophy/tokens": "^1.1.0"
|
|
63
67
|
},
|
|
64
68
|
"devDependencies": {
|
|
65
|
-
"@primereact/ui": "^11.2.0",
|
|
66
69
|
"@storybook/addon-docs": "^9.1.0",
|
|
67
70
|
"@storybook/react": "^9.1.0",
|
|
68
71
|
"@storybook/react-vite": "^9.1.0",
|
|
@@ -71,7 +74,7 @@
|
|
|
71
74
|
"@types/react": "^19.1.0",
|
|
72
75
|
"@types/react-dom": "^19.1.0",
|
|
73
76
|
"jsdom": "^26.1.0",
|
|
74
|
-
"primereact": "^
|
|
77
|
+
"primereact": "^10.9.6",
|
|
75
78
|
"react": "^19.1.0",
|
|
76
79
|
"react-dom": "^19.1.0",
|
|
77
80
|
"storybook": "^9.1.0",
|