anteriority-ui 1.4.0 → 1.5.0
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/.verify-bundle.css +230 -98
- package/.verify-bundle.js +2 -2
- package/AnteriorityUI.md +183 -11
- package/common/icons/index.js +7 -0
- package/index.js +32 -30
- package/package.json +1 -1
- package/screens/components/Callout/index.js +27 -5
- package/screens/components/Callout/index.module.css +21 -0
- package/screens/components/Container/index.js +9 -0
- package/screens/components/Frame/constants.js +8 -0
- package/screens/components/Frame/index.js +28 -6
- package/screens/components/Frame/index.module.css +19 -0
- package/screens/components/IconCatalog/index.js +27 -58
- package/screens/components/IconCatalog/index.module.css +8 -0
- package/screens/components/Icons/findIcons.js +18 -0
- package/screens/components/Icons/registry.js +37 -0
- package/screens/components/NotificationsPanel/constants.js +10 -0
- package/screens/components/NotificationsPanel/index.js +91 -0
- package/screens/components/NotificationsPanel/index.module.css +29 -0
- package/screens/components/ScrollBar/index.js +2 -1
- package/screens/components/ScrollBar/index.module.css +7 -2
- package/screens/components/Sidebar/index.js +73 -32
- package/screens/components/Sidebar/index.module.css +74 -0
- package/screens/components/Sidebar/utils.js +12 -0
package/.verify-bundle.css
CHANGED
|
@@ -1187,9 +1187,25 @@
|
|
|
1187
1187
|
background-color: #ffffff;
|
|
1188
1188
|
z-index: 10;
|
|
1189
1189
|
}
|
|
1190
|
+
.Frame_skeletonGroup {
|
|
1191
|
+
width: 100%;
|
|
1192
|
+
display: flex;
|
|
1193
|
+
flex-direction: column;
|
|
1194
|
+
gap: 0.6rem;
|
|
1195
|
+
}
|
|
1190
1196
|
.Frame_hiddenContent {
|
|
1191
1197
|
visibility: hidden;
|
|
1192
1198
|
}
|
|
1199
|
+
.Frame_contentWrapper {
|
|
1200
|
+
display: flex;
|
|
1201
|
+
flex-direction: column;
|
|
1202
|
+
min-height: 0;
|
|
1203
|
+
width: 100%;
|
|
1204
|
+
}
|
|
1205
|
+
.Frame_scrollContent {
|
|
1206
|
+
display: flex;
|
|
1207
|
+
flex-direction: column;
|
|
1208
|
+
}
|
|
1193
1209
|
|
|
1194
1210
|
/* dist/screens/components/Loading/index.module.css */
|
|
1195
1211
|
.Loading_loadingContainer {
|
|
@@ -1393,6 +1409,108 @@
|
|
|
1393
1409
|
transform: translateY(-4px);
|
|
1394
1410
|
}
|
|
1395
1411
|
|
|
1412
|
+
/* dist/screens/components/Skeleton/index.module.css */
|
|
1413
|
+
.Skeleton_skeleton {
|
|
1414
|
+
position: relative;
|
|
1415
|
+
display: inline-block;
|
|
1416
|
+
overflow: hidden;
|
|
1417
|
+
background: rgba(128, 128, 128, 0.18);
|
|
1418
|
+
}
|
|
1419
|
+
.Skeleton_skeleton::after {
|
|
1420
|
+
content: "";
|
|
1421
|
+
position: absolute;
|
|
1422
|
+
inset: 0;
|
|
1423
|
+
transform: translateX(-100%);
|
|
1424
|
+
background:
|
|
1425
|
+
linear-gradient(
|
|
1426
|
+
90deg,
|
|
1427
|
+
rgba(255, 255, 255, 0) 0%,
|
|
1428
|
+
rgba(255, 255, 255, 0.35) 50%,
|
|
1429
|
+
rgba(255, 255, 255, 0) 100%);
|
|
1430
|
+
animation: Skeleton_skeletonSweep 1.6s ease-in-out infinite;
|
|
1431
|
+
}
|
|
1432
|
+
@keyframes Skeleton_skeletonSweep {
|
|
1433
|
+
100% {
|
|
1434
|
+
transform: translateX(100%);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
/* dist/screens/components/ScrollBar/index.module.css */
|
|
1439
|
+
.ScrollBar_root {
|
|
1440
|
+
position: relative;
|
|
1441
|
+
width: 100%;
|
|
1442
|
+
}
|
|
1443
|
+
.ScrollBar_scrollArea {
|
|
1444
|
+
width: 100%;
|
|
1445
|
+
height: 100%;
|
|
1446
|
+
box-sizing: border-box;
|
|
1447
|
+
scrollbar-width: none;
|
|
1448
|
+
-ms-overflow-style: none;
|
|
1449
|
+
}
|
|
1450
|
+
.ScrollBar_reserveTrackSpace {
|
|
1451
|
+
padding-right: 14px;
|
|
1452
|
+
}
|
|
1453
|
+
.ScrollBar_scrollArea::-webkit-scrollbar {
|
|
1454
|
+
display: none;
|
|
1455
|
+
}
|
|
1456
|
+
.ScrollBar_trackVertical {
|
|
1457
|
+
position: absolute;
|
|
1458
|
+
top: 4px;
|
|
1459
|
+
right: 4px;
|
|
1460
|
+
bottom: 4px;
|
|
1461
|
+
width: 6px;
|
|
1462
|
+
border-radius: 999px;
|
|
1463
|
+
background-color: rgba(148, 163, 184, 0.12);
|
|
1464
|
+
opacity: 0;
|
|
1465
|
+
pointer-events: none;
|
|
1466
|
+
transition: opacity 0.2s ease;
|
|
1467
|
+
z-index: 5;
|
|
1468
|
+
}
|
|
1469
|
+
.ScrollBar_trackHorizontal {
|
|
1470
|
+
position: absolute;
|
|
1471
|
+
left: 4px;
|
|
1472
|
+
right: 4px;
|
|
1473
|
+
bottom: 3px;
|
|
1474
|
+
height: 8px;
|
|
1475
|
+
border-radius: 999px;
|
|
1476
|
+
background-color: rgba(148, 163, 184, 0.12);
|
|
1477
|
+
opacity: 0;
|
|
1478
|
+
pointer-events: none;
|
|
1479
|
+
transition: opacity 0.2s ease;
|
|
1480
|
+
z-index: 5;
|
|
1481
|
+
}
|
|
1482
|
+
.ScrollBar_trackVisible {
|
|
1483
|
+
opacity: 1;
|
|
1484
|
+
}
|
|
1485
|
+
.ScrollBar_thumbVertical {
|
|
1486
|
+
position: absolute;
|
|
1487
|
+
top: 0;
|
|
1488
|
+
right: 0;
|
|
1489
|
+
width: 100%;
|
|
1490
|
+
border-radius: 999px;
|
|
1491
|
+
background-color: rgba(100, 116, 139, 0.45);
|
|
1492
|
+
cursor: pointer;
|
|
1493
|
+
pointer-events: auto;
|
|
1494
|
+
transition: background-color 0.15s ease;
|
|
1495
|
+
}
|
|
1496
|
+
.ScrollBar_thumbHorizontal {
|
|
1497
|
+
position: absolute;
|
|
1498
|
+
left: 0;
|
|
1499
|
+
top: 0;
|
|
1500
|
+
height: 100%;
|
|
1501
|
+
border-radius: 999px;
|
|
1502
|
+
background-color: rgba(100, 116, 139, 0.45);
|
|
1503
|
+
cursor: pointer;
|
|
1504
|
+
pointer-events: auto;
|
|
1505
|
+
transition: background-color 0.15s ease;
|
|
1506
|
+
}
|
|
1507
|
+
.ScrollBar_thumbVertical:hover,
|
|
1508
|
+
.ScrollBar_thumbVertical:active,
|
|
1509
|
+
.ScrollBar_thumbHorizontal:hover,
|
|
1510
|
+
.ScrollBar_thumbHorizontal:active {
|
|
1511
|
+
background-color: rgba(71, 85, 105, 0.75);
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1396
1514
|
/* dist/screens/components/MarkdownContent/index.module.css */
|
|
1397
1515
|
.MarkdownContent_markdown {
|
|
1398
1516
|
font-size: 0.88rem;
|
|
@@ -1598,6 +1716,18 @@
|
|
|
1598
1716
|
border-radius: 8px;
|
|
1599
1717
|
box-sizing: border-box;
|
|
1600
1718
|
animation: Callout_calloutSlideIn 0.2s ease-out;
|
|
1719
|
+
text-decoration: none;
|
|
1720
|
+
}
|
|
1721
|
+
.Callout_clickable {
|
|
1722
|
+
cursor: pointer;
|
|
1723
|
+
transition: filter 0.15s ease, box-shadow 0.15s ease;
|
|
1724
|
+
}
|
|
1725
|
+
.Callout_clickable:hover {
|
|
1726
|
+
filter: brightness(0.97);
|
|
1727
|
+
}
|
|
1728
|
+
.Callout_clickable:focus-visible {
|
|
1729
|
+
outline: 2px solid currentColor;
|
|
1730
|
+
outline-offset: 2px;
|
|
1601
1731
|
}
|
|
1602
1732
|
.Callout_icon {
|
|
1603
1733
|
display: inline-flex;
|
|
@@ -1617,6 +1747,11 @@
|
|
|
1617
1747
|
.Callout_markdownBody {
|
|
1618
1748
|
font-size: 0.85rem;
|
|
1619
1749
|
}
|
|
1750
|
+
.Callout_timestamp {
|
|
1751
|
+
font-size: 0.72rem;
|
|
1752
|
+
opacity: 0.7;
|
|
1753
|
+
margin-top: 4px;
|
|
1754
|
+
}
|
|
1620
1755
|
.Callout_actions {
|
|
1621
1756
|
display: flex;
|
|
1622
1757
|
flex-wrap: wrap;
|
|
@@ -3292,6 +3427,13 @@
|
|
|
3292
3427
|
white-space: normal !important;
|
|
3293
3428
|
overflow-wrap: anywhere !important;
|
|
3294
3429
|
}
|
|
3430
|
+
.IconCatalog_packBadge {
|
|
3431
|
+
font-size: 0.65rem;
|
|
3432
|
+
color: var(--color-text-muted, #64748b);
|
|
3433
|
+
background: var(--color-border, #e2e8f0);
|
|
3434
|
+
border-radius: 999px;
|
|
3435
|
+
padding: 0.1rem 0.5rem;
|
|
3436
|
+
}
|
|
3295
3437
|
.IconCatalog_empty {
|
|
3296
3438
|
font-size: 0.9rem;
|
|
3297
3439
|
color: var(--color-text-muted, #64748b);
|
|
@@ -3612,6 +3754,33 @@
|
|
|
3612
3754
|
margin-top: 2px;
|
|
3613
3755
|
}
|
|
3614
3756
|
|
|
3757
|
+
/* dist/screens/components/NotificationsPanel/index.module.css */
|
|
3758
|
+
.NotificationsPanel_panel {
|
|
3759
|
+
width: 360px;
|
|
3760
|
+
padding: 1.5rem;
|
|
3761
|
+
}
|
|
3762
|
+
.NotificationsPanel_list {
|
|
3763
|
+
display: flex;
|
|
3764
|
+
flex-direction: column;
|
|
3765
|
+
gap: 0.75rem;
|
|
3766
|
+
min-height: 0;
|
|
3767
|
+
}
|
|
3768
|
+
.NotificationsPanel_emptyMessage {
|
|
3769
|
+
margin: 1rem 0;
|
|
3770
|
+
text-align: center;
|
|
3771
|
+
font-size: 0.85rem;
|
|
3772
|
+
color: #94a3b8;
|
|
3773
|
+
}
|
|
3774
|
+
.NotificationsPanel_item {
|
|
3775
|
+
align-items: flex-start;
|
|
3776
|
+
}
|
|
3777
|
+
.NotificationsPanel_itemActions {
|
|
3778
|
+
display: flex;
|
|
3779
|
+
flex-direction: column;
|
|
3780
|
+
gap: 0.5rem;
|
|
3781
|
+
margin-top: 0.25rem;
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3615
3784
|
/* dist/screens/components/ToggleCard/index.module.css */
|
|
3616
3785
|
.ToggleCard_toggleContainer {
|
|
3617
3786
|
background: #ffffff;
|
|
@@ -3859,104 +4028,6 @@
|
|
|
3859
4028
|
}
|
|
3860
4029
|
}
|
|
3861
4030
|
|
|
3862
|
-
/* dist/screens/components/ScrollBar/index.module.css */
|
|
3863
|
-
.ScrollBar_root {
|
|
3864
|
-
position: relative;
|
|
3865
|
-
width: 100%;
|
|
3866
|
-
}
|
|
3867
|
-
.ScrollBar_scrollArea {
|
|
3868
|
-
width: 100%;
|
|
3869
|
-
height: 100%;
|
|
3870
|
-
scrollbar-width: none;
|
|
3871
|
-
-ms-overflow-style: none;
|
|
3872
|
-
}
|
|
3873
|
-
.ScrollBar_scrollArea::-webkit-scrollbar {
|
|
3874
|
-
display: none;
|
|
3875
|
-
}
|
|
3876
|
-
.ScrollBar_trackVertical {
|
|
3877
|
-
position: absolute;
|
|
3878
|
-
top: 4px;
|
|
3879
|
-
right: 3px;
|
|
3880
|
-
bottom: 4px;
|
|
3881
|
-
width: 8px;
|
|
3882
|
-
border-radius: 999px;
|
|
3883
|
-
background-color: rgba(148, 163, 184, 0.12);
|
|
3884
|
-
opacity: 0;
|
|
3885
|
-
pointer-events: none;
|
|
3886
|
-
transition: opacity 0.2s ease;
|
|
3887
|
-
z-index: 5;
|
|
3888
|
-
}
|
|
3889
|
-
.ScrollBar_trackHorizontal {
|
|
3890
|
-
position: absolute;
|
|
3891
|
-
left: 4px;
|
|
3892
|
-
right: 4px;
|
|
3893
|
-
bottom: 3px;
|
|
3894
|
-
height: 8px;
|
|
3895
|
-
border-radius: 999px;
|
|
3896
|
-
background-color: rgba(148, 163, 184, 0.12);
|
|
3897
|
-
opacity: 0;
|
|
3898
|
-
pointer-events: none;
|
|
3899
|
-
transition: opacity 0.2s ease;
|
|
3900
|
-
z-index: 5;
|
|
3901
|
-
}
|
|
3902
|
-
.ScrollBar_trackVisible {
|
|
3903
|
-
opacity: 1;
|
|
3904
|
-
}
|
|
3905
|
-
.ScrollBar_thumbVertical {
|
|
3906
|
-
position: absolute;
|
|
3907
|
-
top: 0;
|
|
3908
|
-
right: 0;
|
|
3909
|
-
width: 100%;
|
|
3910
|
-
border-radius: 999px;
|
|
3911
|
-
background-color: rgba(100, 116, 139, 0.45);
|
|
3912
|
-
cursor: pointer;
|
|
3913
|
-
pointer-events: auto;
|
|
3914
|
-
transition: background-color 0.15s ease;
|
|
3915
|
-
}
|
|
3916
|
-
.ScrollBar_thumbHorizontal {
|
|
3917
|
-
position: absolute;
|
|
3918
|
-
left: 0;
|
|
3919
|
-
top: 0;
|
|
3920
|
-
height: 100%;
|
|
3921
|
-
border-radius: 999px;
|
|
3922
|
-
background-color: rgba(100, 116, 139, 0.45);
|
|
3923
|
-
cursor: pointer;
|
|
3924
|
-
pointer-events: auto;
|
|
3925
|
-
transition: background-color 0.15s ease;
|
|
3926
|
-
}
|
|
3927
|
-
.ScrollBar_thumbVertical:hover,
|
|
3928
|
-
.ScrollBar_thumbVertical:active,
|
|
3929
|
-
.ScrollBar_thumbHorizontal:hover,
|
|
3930
|
-
.ScrollBar_thumbHorizontal:active {
|
|
3931
|
-
background-color: rgba(71, 85, 105, 0.75);
|
|
3932
|
-
}
|
|
3933
|
-
|
|
3934
|
-
/* dist/screens/components/Skeleton/index.module.css */
|
|
3935
|
-
.Skeleton_skeleton {
|
|
3936
|
-
position: relative;
|
|
3937
|
-
display: inline-block;
|
|
3938
|
-
overflow: hidden;
|
|
3939
|
-
background: rgba(128, 128, 128, 0.18);
|
|
3940
|
-
}
|
|
3941
|
-
.Skeleton_skeleton::after {
|
|
3942
|
-
content: "";
|
|
3943
|
-
position: absolute;
|
|
3944
|
-
inset: 0;
|
|
3945
|
-
transform: translateX(-100%);
|
|
3946
|
-
background:
|
|
3947
|
-
linear-gradient(
|
|
3948
|
-
90deg,
|
|
3949
|
-
rgba(255, 255, 255, 0) 0%,
|
|
3950
|
-
rgba(255, 255, 255, 0.35) 50%,
|
|
3951
|
-
rgba(255, 255, 255, 0) 100%);
|
|
3952
|
-
animation: Skeleton_skeletonSweep 1.6s ease-in-out infinite;
|
|
3953
|
-
}
|
|
3954
|
-
@keyframes Skeleton_skeletonSweep {
|
|
3955
|
-
100% {
|
|
3956
|
-
transform: translateX(100%);
|
|
3957
|
-
}
|
|
3958
|
-
}
|
|
3959
|
-
|
|
3960
4031
|
/* dist/screens/components/Sidebar/index.module.css */
|
|
3961
4032
|
.Sidebar_sidebar {
|
|
3962
4033
|
height: 100vh;
|
|
@@ -4178,6 +4249,67 @@
|
|
|
4178
4249
|
.Sidebar_sidebarItemBtn:hover .Sidebar_icon {
|
|
4179
4250
|
color: var(--sidebar-text-active) !important;
|
|
4180
4251
|
}
|
|
4252
|
+
.Sidebar_itemWithSubItems {
|
|
4253
|
+
display: flex;
|
|
4254
|
+
flex-direction: column;
|
|
4255
|
+
}
|
|
4256
|
+
.Sidebar_expandChevron {
|
|
4257
|
+
flex-shrink: 0;
|
|
4258
|
+
color: var(--sidebar-text-muted);
|
|
4259
|
+
opacity: 0.7;
|
|
4260
|
+
transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
|
|
4261
|
+
}
|
|
4262
|
+
.Sidebar_expandChevronOpen {
|
|
4263
|
+
transform: rotate(180deg);
|
|
4264
|
+
opacity: 1;
|
|
4265
|
+
}
|
|
4266
|
+
.Sidebar_expandParentOpen {
|
|
4267
|
+
color: var(--sidebar-text-active) !important;
|
|
4268
|
+
font-weight: 600 !important;
|
|
4269
|
+
}
|
|
4270
|
+
.Sidebar_expandParentOpen .Sidebar_icon {
|
|
4271
|
+
color: var(--sidebar-text-active) !important;
|
|
4272
|
+
}
|
|
4273
|
+
.Sidebar_subItemListWrapper {
|
|
4274
|
+
display: grid;
|
|
4275
|
+
grid-template-rows: 0fr;
|
|
4276
|
+
margin-top: 0;
|
|
4277
|
+
transition: grid-template-rows 0.28s cubic-bezier(0.4, 0, 0.2, 1), margin-top 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
|
4278
|
+
}
|
|
4279
|
+
.Sidebar_subItemListWrapperOpen {
|
|
4280
|
+
grid-template-rows: 1fr;
|
|
4281
|
+
margin-top: 2px;
|
|
4282
|
+
}
|
|
4283
|
+
.Sidebar_subItemList {
|
|
4284
|
+
overflow: hidden;
|
|
4285
|
+
display: flex;
|
|
4286
|
+
flex-direction: column;
|
|
4287
|
+
gap: 2px;
|
|
4288
|
+
margin-left: 29px;
|
|
4289
|
+
padding: 2px 0 2px 14px;
|
|
4290
|
+
border-left: 1.5px solid var(--sidebar-border);
|
|
4291
|
+
opacity: 0;
|
|
4292
|
+
transform: translateY(-4px);
|
|
4293
|
+
transition: opacity 0.16s ease, transform 0.16s ease;
|
|
4294
|
+
}
|
|
4295
|
+
.Sidebar_subItemListWrapperOpen .Sidebar_subItemList {
|
|
4296
|
+
opacity: 1;
|
|
4297
|
+
transform: translateY(0);
|
|
4298
|
+
transition: opacity 0.22s ease 0.08s, transform 0.22s ease 0.08s;
|
|
4299
|
+
}
|
|
4300
|
+
.Sidebar_subItemBtn {
|
|
4301
|
+
padding: 7px 10px !important;
|
|
4302
|
+
min-height: 0 !important;
|
|
4303
|
+
}
|
|
4304
|
+
.Sidebar_subItemBtn .Sidebar_label {
|
|
4305
|
+
font-size: 0.82rem;
|
|
4306
|
+
font-weight: 500;
|
|
4307
|
+
}
|
|
4308
|
+
.Sidebar_subItemBtn.Sidebar_activeBtn {
|
|
4309
|
+
background-color: var(--sidebar-subitem-active-bg, #e0edff) !important;
|
|
4310
|
+
color: var(--sidebar-subitem-active-text, #1d4ed8) !important;
|
|
4311
|
+
font-weight: 600 !important;
|
|
4312
|
+
}
|
|
4181
4313
|
.Sidebar_activeBtn {
|
|
4182
4314
|
background-color: var(--sidebar-hover-bg) !important;
|
|
4183
4315
|
color: var(--sidebar-text-active) !important;
|
package/.verify-bundle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/.verify-bundle.js
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 53387707 bytes
|
|
4
|
+
sha256: 95636eacde0da07e512202f5b6d0bb1bf9bd83b31d3484db025dc95b3935b7cf
|
package/AnteriorityUI.md
CHANGED
|
@@ -440,7 +440,7 @@ En modo `range`, la selección soporta dos gestos, intercambiables: (1) click en
|
|
|
440
440
|
|
|
441
441
|
### Callout
|
|
442
442
|
|
|
443
|
-
Caja de aviso/notificación (advertencia, error, éxito, info, nota neutral) con ícono y paleta de color por `variant`, título opcional y cuerpo en Markdown completo (listas, negrita, links, bloques de código, tablas, etc. — reutiliza `MarkdownContent` por dentro). Pensado para usarse suelto en una vista, dentro de `DrawPanel`/`Frame`, o como notificación.
|
|
443
|
+
Caja de aviso/notificación (advertencia, error, éxito, info, nota neutral) con ícono y paleta de color por `variant`, título opcional, timestamp opcional y cuerpo en Markdown completo (listas, negrita, links, bloques de código, tablas, etc. — reutiliza `MarkdownContent` por dentro). Pensado para usarse suelto en una vista, dentro de `DrawPanel`/`Frame`, o como notificación (es el building block que usa `NotificationsPanel` para cada item de la lista). Opcionalmente clickeable/navegable vía `onClick`/`href`.
|
|
444
444
|
|
|
445
445
|
**Import:**
|
|
446
446
|
```jsx
|
|
@@ -461,10 +461,13 @@ import Callout from '../Callout/index'; // export default
|
|
|
461
461
|
| `variant` | `'info'` \| `'warning'` \| `'danger'` \| `'success'` \| `'neutral'` | `'info'` | Determina paleta (fondo/borde/texto/ícono) e ícono por default. |
|
|
462
462
|
| `title` | string | — | Título en negrita sobre el cuerpo. |
|
|
463
463
|
| `children` | string | — | Cuerpo en Markdown (mismo formato que `MarkdownContent`). |
|
|
464
|
+
| `timestamp` | string | — | Texto pequeño (ej. `"Hace 5 minutos"`) mostrado debajo del cuerpo. |
|
|
464
465
|
| `icon` | component | — | Reemplaza el ícono default del `variant`. |
|
|
465
|
-
| `actions` | node | — | Contenido (ej. botones) renderizado debajo del cuerpo. |
|
|
466
|
-
| `onClose` | `function()` | — | Si se define, muestra un botón de cerrar (×) arriba a la derecha. |
|
|
466
|
+
| `actions` | node | — | Contenido (ej. botones) renderizado debajo del cuerpo. Los clicks dentro de `actions` no disparan `onClick`/`href` del Callout (`stopPropagation`). |
|
|
467
|
+
| `onClose` | `function()` | — | Si se define, muestra un botón de cerrar (×) arriba a la derecha. Su click tampoco dispara `onClick`/`href`. |
|
|
467
468
|
| `closeLabel` | string | `'Cerrar aviso'` | `aria-label` del botón de cerrar. |
|
|
469
|
+
| `onClick` | `function(event)` | — | Si se define (y no hay `href`), el Callout entero se vuelve clickeable: se renderiza como `<div role="button" tabIndex={0}>` con soporte de teclado (Enter/Espacio) y cursor pointer. |
|
|
470
|
+
| `href` | string | — | Si se define, el Callout se renderiza como `<a href={href}>` (navegación nativa: Ctrl+click, abrir en pestaña nueva, etc.). Tiene prioridad sobre `onClick` como tag, pero `onClick` igual se dispara si también se pasa. |
|
|
468
471
|
| `bgColor` | string | — | Sobrescribe el color de fondo de la paleta del `variant`. |
|
|
469
472
|
| `textColor` | string | — | Sobrescribe el color del título y del cuerpo (markdown incluido). |
|
|
470
473
|
| `iconColor` | string | — | Sobrescribe el color del ícono. |
|
|
@@ -1123,7 +1126,7 @@ import { FormCard, FormInput, FormTextArea } from '../FormControls/index'; // na
|
|
|
1123
1126
|
|
|
1124
1127
|
### Frame
|
|
1125
1128
|
|
|
1126
|
-
Contenedor tipo "card" con título, ícono, descripción y estado de error/carga opcionales. Puede renderizarse inline o como modal (overlay + portal).
|
|
1129
|
+
Contenedor tipo "card" con título, ícono, descripción y estado de error/carga opcionales. Puede renderizarse inline o como modal (overlay + portal). Opcionalmente scrollea su contenido internamente (vía `ScrollBar`, sin barra de scroll nativa) cuando el contenido supera un alto máximo.
|
|
1127
1130
|
|
|
1128
1131
|
**Import:**
|
|
1129
1132
|
```jsx
|
|
@@ -1147,7 +1150,12 @@ import Frame from '../Frame/index'; // export default, archivo index.jsx
|
|
|
1147
1150
|
| className | string | `''` | Clase(s) CSS adicionales. |
|
|
1148
1151
|
| isModal | boolean | `false` | Si es `true`, renderiza el frame como overlay modal vía `createPortal` a `document.body`. |
|
|
1149
1152
|
| onClose | function | — | Se ejecuta al hacer click en el overlay (solo aplica con `isModal`). |
|
|
1150
|
-
| isLoading | boolean | `false` | Muestra un overlay
|
|
1153
|
+
| isLoading | boolean | `false` | Muestra un overlay sobre el contenido (oculto con `visibility: hidden`, no desmontado) mientras carga. El tipo de overlay lo decide `loadingType`. |
|
|
1154
|
+
| loadingType | `'spinner'` \| `'skeleton'` | `'spinner'` | Con `isLoading`: `'spinner'` muestra `Loading` (`size="giant"`); `'skeleton'` muestra `skeletonCount` barras `Skeleton` genéricas apiladas. |
|
|
1155
|
+
| loadingVariant | string | `'default'` | Con `loadingType="spinner"`, se pasa tal cual como prop `variant` a `Loading` (`'default'` \| `'bars'` \| `'bounce'` \| `'box'`). |
|
|
1156
|
+
| skeletonCount | number | `3` | Con `loadingType="skeleton"`, cantidad de barras `Skeleton` a mostrar. |
|
|
1157
|
+
| scrollable | boolean | `false` | Si es `true`, envuelve `children` con `ScrollBar` (scroll interno sin barra nativa, thumb delgado visible solo on hover/scroll). |
|
|
1158
|
+
| maxHeight | number \| string | — | Con `scrollable`, alto máximo del área scrolleable (pasa a `ScrollBar` como `maxHeight`). Sin `maxHeight`, el contenido crece libremente (el `ScrollBar` no limita el alto por sí solo). |
|
|
1151
1159
|
| bgColor | string | — | Color de fondo del frame (`--frame-bg`). |
|
|
1152
1160
|
| iconColor | string | — | Color del contenedor del ícono (`--frame-icon`). |
|
|
1153
1161
|
| descriptionBgColor | string | — | Color de fondo del texto de descripción (`--frame-description-bg`). |
|
|
@@ -1161,8 +1169,20 @@ import Frame from '../Frame/index'; // export default, archivo index.jsx
|
|
|
1161
1169
|
<p>Este contenido queda oculto mientras carga.</p>
|
|
1162
1170
|
</Frame>
|
|
1163
1171
|
```
|
|
1172
|
+
```jsx
|
|
1173
|
+
// Overlay tipo skeleton en vez del spinner default
|
|
1174
|
+
<Frame title="Cargando datos" isLoading loadingType="skeleton" skeletonCount={4}>
|
|
1175
|
+
<p>Este contenido queda oculto mientras carga.</p>
|
|
1176
|
+
</Frame>
|
|
1177
|
+
```
|
|
1178
|
+
```jsx
|
|
1179
|
+
// Lista larga con scroll interno (sin barra de scroll nativa)
|
|
1180
|
+
<Frame title="Lista larga" scrollable maxHeight={220}>
|
|
1181
|
+
{items.map((item) => <p key={item.id}>{item.label}</p>)}
|
|
1182
|
+
</Frame>
|
|
1183
|
+
```
|
|
1164
1184
|
|
|
1165
|
-
**Notas:** `isModal` renderiza vía `createPortal` sobre `document.body` con un overlay que cierra al hacer click fuera (así lo usa internamente `HoursPicker`).
|
|
1185
|
+
**Notas:** `isModal` renderiza vía `createPortal` sobre `document.body` con un overlay que cierra al hacer click fuera (así lo usa internamente `HoursPicker`). El estado `isLoading` depende de `Loading` (modo `'spinner'`, default) o de `Skeleton` (modo `'skeleton'`) — el skeleton es genérico (barras simples) porque `Frame` no conoce la forma real del contenido de cada consumidor; componentes como `NotificationsPanel` exponen las mismas props (`isLoading`/`loadingType`/`loadingVariant`/`skeletonCount`/`scrollable` vía `maxHeight`) y simplemente las reenvían a su `Frame` interno en vez de reimplementar loading o scroll por su cuenta.
|
|
1166
1186
|
|
|
1167
1187
|
---
|
|
1168
1188
|
|
|
@@ -1281,7 +1301,31 @@ import { VscJson } from 'anteriority-ui/screens/components/Icons/vsc';
|
|
|
1281
1301
|
|
|
1282
1302
|
**Packs disponibles:** cada pack de react-icons se expone en `screens/components/Icons/<pack>`, con el mismo nombre de carpeta que usa react-icons: `ai`, `bi`, `bs`, `cg`, `ci`, `di`, `fa`, `fa6`, `fc`, `fi`, `gi`, `go`, `gr`, `hi`, `hi2`, `im`, `io`, `io5`, `lia`, `lu`, `md`, `pi`, `ri`, `rx`, `si`, `sl`, `tb`, `tfi`, `ti`, `vsc`, `wi`.
|
|
1283
1303
|
|
|
1284
|
-
**Notas:** Los nombres de cada ícono son exactamente los que exporta react-icons — usar el [buscador oficial](https://react-icons.github.io/react-icons/)
|
|
1304
|
+
**Notas:** Los nombres de cada ícono son exactamente los que exporta react-icons — usar el [buscador oficial](https://react-icons.github.io/react-icons/), el componente [IconCatalog](#iconcatalog) o la función [findIcons](#findicons) para encontrar el nombre exacto dentro de su pack. `si` (Simple Icons) es el pack más relevante para logos de marcas/lenguajes/herramientas (JavaScript, YAML, Docker, etc.), pero **no tiene cobertura total** — por ejemplo no existe un ícono de C# en `si`; ese logo vive en los packs `tb` (`TbBrandCSharp`) y `pi` (`PiFileCSharp`). Si un ícono no aparece en `si`, buscarlo en otros packs antes de asumir que no está disponible — o usar `findIcons`, que ya busca en los 31 a la vez. Packs como `fa` o `md` cubren además íconos genéricos de tipo de archivo (audio, pdf, imagen) que no tienen un logo de marca propio. Los archivos `screens/components/Icons/<pack>/index.js` son re-exports de 1 línea generados por `node scripts/generate-icon-packs.mjs` (correr de nuevo solo si react-icons agrega o quita un pack); quedan versionados en el repo como cualquier otro archivo fuente, no se regeneran en cada build. `screens/components/Icons/registry.js` centraliza el import de los 31 packs (`ICON_PACKS`, `ICON_PACK_NAMES`) — tanto `IconCatalog` como `findIcons` lo reusan en vez de repetir la lista de imports.
|
|
1305
|
+
|
|
1306
|
+
---
|
|
1307
|
+
|
|
1308
|
+
### findIcons
|
|
1309
|
+
|
|
1310
|
+
Busca un término (substring, case-insensitive) en el nombre de ícono de **todos** los packs de react-icons a la vez, sin necesidad de saber de antemano en qué pack vive cada uno. Pensada para resolver casos como "necesito el logo de C#" sin tener que adivinar o probar pack por pack — `findIcons('csharp')` ya devuelve los matches de `tb`, `pi`, etc. en un solo llamado.
|
|
1311
|
+
|
|
1312
|
+
**Import:**
|
|
1313
|
+
```jsx
|
|
1314
|
+
import { findIcons } from 'anteriority-ui/common/icons';
|
|
1315
|
+
```
|
|
1316
|
+
|
|
1317
|
+
**Uso básico:**
|
|
1318
|
+
```jsx
|
|
1319
|
+
const results = findIcons('csharp');
|
|
1320
|
+
// [{ pack: 'tb', name: 'TbBrandCSharp', Icon: [Function] }, { pack: 'pi', name: 'PiFileCSharp', Icon: [Function] }, ...]
|
|
1321
|
+
|
|
1322
|
+
const { Icon } = results[0];
|
|
1323
|
+
<Icon size={24} />
|
|
1324
|
+
```
|
|
1325
|
+
|
|
1326
|
+
**Firma:** `findIcons(query: string) => { pack: string, name: string, Icon: ComponentType }[]`
|
|
1327
|
+
|
|
1328
|
+
**Notas:** Es una utilidad de **búsqueda en runtime**, no un import estático — devuelve el componente ya resuelto (`Icon`), listo para renderizar, pero no reemplaza el subpath import para un ícono que ya se conoce (ver [Icons (react-icons)](#icons-react-icons)), que sigue siendo más explícito y con mejor tree-shaking cuando el nombre exacto ya está decidido. Con query vacío devuelve `[]`. Puede devolver cientos de resultados con términos muy cortos/genéricos (ej. `'a'`) — conviene truncar/paginar en la UI que consuma el resultado, como hace [IconCatalog](#iconcatalog) internamente. También se puede usar directo desde `anteriority-ui/screens/components/Icons/findIcons` (el subpath real); `anteriority-ui/common/icons` es solo un alias más corto.
|
|
1285
1329
|
|
|
1286
1330
|
---
|
|
1287
1331
|
|
|
@@ -1931,6 +1975,107 @@ import ErrorMessage from 'screens/components/Notification/Error/ErrorMessage';
|
|
|
1931
1975
|
|
|
1932
1976
|
---
|
|
1933
1977
|
|
|
1978
|
+
### NotificationsPanel
|
|
1979
|
+
|
|
1980
|
+
Panel de notificaciones construido sobre `Frame` (header con ícono de campana + título). Cada notificación se renderiza con `Callout` (título, mensaje en Markdown, timestamp, ícono, paleta por `variant`, botones de acción vía `Button`, botón de descarte (×) y soporte de click/navegación). La lista scrollea internamente (vía la prop `scrollable` de `Frame`, que a su vez usa `ScrollBar`) sin mostrar una barra de scroll nativa — el thumb queda oculto hasta hover/scroll. Soporta modo inline o modal (overlay + portal) y loading en dos variantes (spinner o skeleton), todo heredado de `Frame`.
|
|
1981
|
+
|
|
1982
|
+
**Import:**
|
|
1983
|
+
```jsx
|
|
1984
|
+
import NotificationsPanel from '../NotificationsPanel/index'; // export default
|
|
1985
|
+
```
|
|
1986
|
+
|
|
1987
|
+
**Uso básico:**
|
|
1988
|
+
```jsx
|
|
1989
|
+
<NotificationsPanel
|
|
1990
|
+
notifications={[
|
|
1991
|
+
{
|
|
1992
|
+
id: 1,
|
|
1993
|
+
title: 'Nueva cita agendada - Firulais',
|
|
1994
|
+
message: 'Se agendó una cita para Firulais el 08/10/2026 a las 15:00 con el Dr. Doctor Doctor.',
|
|
1995
|
+
timestamp: 'Hace 5 minutos',
|
|
1996
|
+
actions: [
|
|
1997
|
+
{ label: 'Confirmar asistencia', variant: 'primary', onClick: () => {} },
|
|
1998
|
+
{ label: 'No podré asistir', variant: 'outline', color: 'red', onClick: () => {} },
|
|
1999
|
+
],
|
|
2000
|
+
},
|
|
2001
|
+
]}
|
|
2002
|
+
onDismiss={(id) => console.log('quitar', id)}
|
|
2003
|
+
/>
|
|
2004
|
+
```
|
|
2005
|
+
|
|
2006
|
+
**Props:**
|
|
2007
|
+
|
|
2008
|
+
| Prop | Tipo | Default | Descripción |
|
|
2009
|
+
|---|---|---|---|
|
|
2010
|
+
| `title` | string | `'Notificaciones'` | Título del header (prop `title` de `Frame`). |
|
|
2011
|
+
| `icon` | node | `<Bell size={20} />` | Ícono del header (prop `icon` de `Frame`). |
|
|
2012
|
+
| `notifications` | array | `[]` | Lista de notificaciones. Cada item acepta: `{ id, title?, message?, timestamp?, icon?, variant?, actions?, onClick?, href?, bgColor?, borderColor?, iconColor?, textColor? }`. `message` se pasa como `children` de `Callout` (acepta Markdown). `actions` es un array de `{ key?, label, variant?, color?, fullWidth?, onClick? }`, renderizados con `Button`. `variant` es la misma paleta de `Callout` (`'info'` \| `'warning'` \| `'danger'` \| `'success'` \| `'neutral'`, default `'neutral'`). `onClick`/`href` hacen la tarjeta entera clickeable/navegable (ver `Callout`). Los `bgColor`/`borderColor`/`iconColor`/`textColor` del item individual tienen prioridad sobre los equivalentes globales del panel (`itemBgColor`, etc.). |
|
|
2013
|
+
| `onDismiss` | `function(id)` | — | Si se define, cada tarjeta muestra un botón (×) que lo invoca con el `id` de la notificación. El panel no quita el item solo — el consumidor controla el array `notifications` (ver ejemplo `Dismissible` en Storybook). |
|
|
2014
|
+
| `emptyMessage` | string | `'No tenés notificaciones nuevas.'` | Texto mostrado cuando `notifications` está vacío. |
|
|
2015
|
+
| `maxHeight` | number | `380` | Alto máximo (px) del área scrolleable (pasa a `Frame` como `maxHeight`, junto con `scrollable` activado automáticamente cuando hay notificaciones). |
|
|
2016
|
+
| `dismissLabel` | string | `'Quitar notificación'` | `aria-label` del botón de descarte (pasa a `Callout` como `closeLabel`). |
|
|
2017
|
+
| `isModal` | boolean | `false` | Renderiza como overlay modal (pasa a `Frame`). |
|
|
2018
|
+
| `onClose` | function | — | Click en el overlay cuando `isModal` (pasa a `Frame`). |
|
|
2019
|
+
| `isLoading` | boolean | `false` | Muestra el overlay de carga de `Frame` (spinner o skeleton genérico) en vez de la lista. |
|
|
2020
|
+
| `loadingType` | `'spinner'` \| `'skeleton'` | `'spinner'` (default de `Frame`) | Tipo de loading cuando `isLoading` (pasa a `Frame`). |
|
|
2021
|
+
| `loadingVariant` | string | `'default'` (default de `Frame`) | Con `loadingType="spinner"`, variant de `Loading` (pasa a `Frame`). |
|
|
2022
|
+
| `skeletonCount` | number | `3` (default de `Frame`) | Con `loadingType="skeleton"`, cantidad de barras `Skeleton` (pasa a `Frame`). |
|
|
2023
|
+
| `className` | string | `''` | Clase adicional en el `Frame` raíz. |
|
|
2024
|
+
| `bgColor` | string | — | Color de fondo del panel (pasa a `Frame` como `bgColor`). |
|
|
2025
|
+
| `iconColor` | string | — | Color del ícono del header — la campana (pasa a `Frame` como `iconColor`). |
|
|
2026
|
+
| `itemBgColor` | string | — | Color de fondo por default de cada tarjeta (pasa a `Callout` como `bgColor`; cada item puede pisarlo con su propio `bgColor`). |
|
|
2027
|
+
| `itemBorderColor` | string | — | Color de borde por default de cada tarjeta (pasa a `Callout` como `borderColor`; pisable por item). |
|
|
2028
|
+
| `itemIconColor` | string | — | Color del ícono por default de cada tarjeta (pasa a `Callout` como `iconColor`; pisable por item). |
|
|
2029
|
+
| `textColor` | string | — | Color de texto (título + mensaje + timestamp) por default de cada tarjeta (pasa a `Callout`; pisable por item). |
|
|
2030
|
+
|
|
2031
|
+
**Ejemplos:**
|
|
2032
|
+
```jsx
|
|
2033
|
+
// Vacío
|
|
2034
|
+
<NotificationsPanel notifications={[]} />
|
|
2035
|
+
|
|
2036
|
+
// Con descarte controlado por el consumidor
|
|
2037
|
+
function Example() {
|
|
2038
|
+
const [items, setItems] = useState(notifications);
|
|
2039
|
+
return (
|
|
2040
|
+
<NotificationsPanel
|
|
2041
|
+
notifications={items}
|
|
2042
|
+
onDismiss={(id) => setItems((prev) => prev.filter((n) => n.id !== id))}
|
|
2043
|
+
/>
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// Como modal
|
|
2048
|
+
<NotificationsPanel notifications={notifications} isModal onClose={() => setOpen(false)} />
|
|
2049
|
+
|
|
2050
|
+
// Loading tipo skeleton
|
|
2051
|
+
<NotificationsPanel notifications={[]} isLoading loadingType="skeleton" skeletonCount={4} />
|
|
2052
|
+
|
|
2053
|
+
// Notificación clickeable (navega al hacer click) y con paleta/colores propios
|
|
2054
|
+
<NotificationsPanel
|
|
2055
|
+
notifications={[
|
|
2056
|
+
{
|
|
2057
|
+
id: 1,
|
|
2058
|
+
variant: 'danger',
|
|
2059
|
+
title: 'Pago rechazado',
|
|
2060
|
+
message: 'No se pudo procesar el pago.',
|
|
2061
|
+
onClick: () => navigate('/facturas/00234'),
|
|
2062
|
+
},
|
|
2063
|
+
{
|
|
2064
|
+
id: 2,
|
|
2065
|
+
title: 'Con colores propios',
|
|
2066
|
+
message: 'Esta tarjeta define su propio bgColor/borderColor/textColor.',
|
|
2067
|
+
bgColor: '#ecfdf5',
|
|
2068
|
+
borderColor: '#a7f3d0',
|
|
2069
|
+
textColor: '#065f46',
|
|
2070
|
+
},
|
|
2071
|
+
]}
|
|
2072
|
+
/>
|
|
2073
|
+
```
|
|
2074
|
+
|
|
2075
|
+
**Notas:** No persiste ni elimina notificaciones por su cuenta — es UI pura (ver regla de separación en `CLAUDE.md`). `onDismiss` solo informa el `id`; el array `notifications` sigue siendo responsabilidad de quien lo use. El contenedor interno aplica `overflow` vía `ScrollBar`, que oculta el track nativo del navegador y muestra un thumb delgado solo mientras se hace hover/scroll. Cada tarjeta es un `Callout` — para personalizar algo no cubierto por las props de `NotificationsPanel` (ej. `linkColor`, `markdownComponents`), usar `Callout` directamente en vez de este componente.
|
|
2076
|
+
|
|
2077
|
+
---
|
|
2078
|
+
|
|
1934
2079
|
### PasswordResetPanel
|
|
1935
2080
|
|
|
1936
2081
|
Panel deslizante (basado en `DrawPanel`) para que un administrador solicite y complete el restablecimiento de contraseña de un usuario, incluyendo lista de solicitudes pendientes, polling de estado y asignación de nueva clave.
|
|
@@ -2128,6 +2273,7 @@ import ScrollBar from 'screens/components/ScrollBar';
|
|
|
2128
2273
|
| `maxHeight` | `string` \| `number` | — | Altura máxima del área scrolleable. |
|
|
2129
2274
|
| `hideHorizontalTrack` | `boolean` | `false` | Oculta el thumb/track horizontal propio (el scroll sigue funcionando). Lo usa `TableA` cuando muestra su pie de desplazamiento. |
|
|
2130
2275
|
| `hideVerticalTrack` | `boolean` | `false` | Oculta el thumb/track vertical propio (el scroll sigue funcionando). Lo usa `TableA`/`TableB` con `stickyHeader`. |
|
|
2276
|
+
| `reserveTrackSpace` | `boolean` | `false` | Reserva `padding-right` en el área de scroll para que el thumb vertical no quede superpuesto sobre el contenido (texto/botones). Pensado para listas verticales de tarjetas (lo usa `Frame` cuando `scrollable`); no afecta el ancho de tablas con scroll horizontal porque es opt-in. |
|
|
2131
2277
|
| `scrollAreaRef` | `ref` \| `function` | — | Recibe el elemento del área de scroll interna, para poder leer o mover `scrollLeft`/`scrollTop` desde afuera. |
|
|
2132
2278
|
| `className` | `string` | `''` | Clase adicional para el contenedor raíz. |
|
|
2133
2279
|
| `contentClassName` | `string` | `''` | Clase adicional para el área de scroll interna. |
|
|
@@ -2146,7 +2292,7 @@ import ScrollBar from 'screens/components/ScrollBar';
|
|
|
2146
2292
|
|
|
2147
2293
|
### Sidebar
|
|
2148
2294
|
|
|
2149
|
-
Barra lateral de navegación colapsable con grupos de items, badges por método HTTP, menú de usuario, menú contextual por item (editar/eliminar/fijar/colaboradores) y reordenamiento por drag & drop.
|
|
2295
|
+
Barra lateral de navegación colapsable con grupos de items, subitems anidados y colapsables (ej. "Vacunas" → Ver/Crear/Pendientes/Lotes), badges por método HTTP, menú de usuario, menú contextual por item (editar/eliminar/fijar/colaboradores) y reordenamiento por drag & drop.
|
|
2150
2296
|
|
|
2151
2297
|
**Import:**
|
|
2152
2298
|
```jsx
|
|
@@ -2168,8 +2314,8 @@ import Sidebar from 'screens/components/Sidebar/index';
|
|
|
2168
2314
|
|
|
2169
2315
|
| Prop | Tipo | Default | Descripción |
|
|
2170
2316
|
|---|---|---|---|
|
|
2171
|
-
| `groups` | `Array<{ title?, items: Array<{ id, label, icon?, badge?, badgeType?, pinned?, isOwner?, isShared? }> }>` | — | Estructura de grupos e items del menú. |
|
|
2172
|
-
| `activeId` | `string`\|`number` | — | Id del item actualmente activo. |
|
|
2317
|
+
| `groups` | `Array<{ title?, items: Array<{ id, label, icon?, badge?, badgeType?, pinned?, isOwner?, isShared?, subItems? }> }>` | — | Estructura de grupos e items del menú. `subItems` es un array opcional de `{ id, label, icon?, badge?, badgeType? }`: si un item lo tiene, se renderiza como header colapsable (con chevron) en vez de item navegable — el click solo expande/colapsa, no dispara `onSelect` ni se marca "activo" (ver Notas). |
|
|
2318
|
+
| `activeId` | `string`\|`number` | — | Id del item (o subitem) actualmente activo. Si matchea el id de un subitem, ese subitem se resalta y su grupo padre se auto-expande al montar el componente. |
|
|
2173
2319
|
| `onSelect` | `function(item)` | — | Callback al seleccionar un item. |
|
|
2174
2320
|
| `collapsible` | `boolean` | `true` | Muestra el botón de colapsar y habilita el atajo de teclado para colapsar/expandir. |
|
|
2175
2321
|
| `loading` | `boolean` | `false` | Muestra `skeletonItems` filas de `Skeleton` en vez de los grupos reales. |
|
|
@@ -2192,6 +2338,32 @@ import Sidebar from 'screens/components/Sidebar/index';
|
|
|
2192
2338
|
|
|
2193
2339
|
**Ejemplos:**
|
|
2194
2340
|
```jsx
|
|
2341
|
+
// Item con subItems colapsables (ej. "Vacunas")
|
|
2342
|
+
<Sidebar
|
|
2343
|
+
groups={[
|
|
2344
|
+
{
|
|
2345
|
+
title: 'General',
|
|
2346
|
+
items: [
|
|
2347
|
+
{ id: 'home', label: 'Inicio', icon: Home },
|
|
2348
|
+
{
|
|
2349
|
+
id: 'vaccines',
|
|
2350
|
+
label: 'Vacunas',
|
|
2351
|
+
icon: Activity,
|
|
2352
|
+
subItems: [
|
|
2353
|
+
{ id: 'vaccines-view', label: 'Ver vacunas' },
|
|
2354
|
+
{ id: 'vaccines-create', label: 'Crear vacuna' },
|
|
2355
|
+
{ id: 'vaccines-pending', label: 'Vacunas pendientes' },
|
|
2356
|
+
{ id: 'vaccines-batches', label: 'Lotes de vacunas' },
|
|
2357
|
+
],
|
|
2358
|
+
},
|
|
2359
|
+
],
|
|
2360
|
+
},
|
|
2361
|
+
]}
|
|
2362
|
+
activeId="vaccines-view"
|
|
2363
|
+
onSelect={(item) => setActiveId(item.id)}
|
|
2364
|
+
user={{ email: 'jane.doe@example.com' }}
|
|
2365
|
+
/>
|
|
2366
|
+
|
|
2195
2367
|
<Sidebar groups={[]} loading skeletonItems={8} user={{ email: 'jane.doe@example.com' }} />
|
|
2196
2368
|
|
|
2197
2369
|
<Sidebar
|
|
@@ -2215,7 +2387,7 @@ import Sidebar from 'screens/components/Sidebar/index';
|
|
|
2215
2387
|
/>
|
|
2216
2388
|
```
|
|
2217
2389
|
|
|
2218
|
-
**Notas:** Persiste el estado colapsado en `localStorage` bajo la clave `sidebar_collapsed`.
|
|
2390
|
+
**Notas:** Persiste el estado colapsado en `localStorage` bajo la clave `sidebar_collapsed`. Los subitems no soportan drag & drop (`onReorderItems`), menú contextual (`onItemEdit`/`onItemDelete`/`onItemPin`/`onItemCollaborators`) ni colapsado individual persistido — solo navegación simple vía `onSelect`. Cuando el sidebar está colapsado (`isCollapsed`), los grupos con `subItems` se muestran colapsados y sin chevron (igual que cualquier item simple, con tooltip); hay que expandir el sidebar para ver/navegar los subitems. `onSearch`/`filterMenuGroups` matchea por `label` del item padre o de cualquiera de sus `subItems`, pero si matchea, se muestra el item completo con **todos** sus subitems (no solo el que matcheó).
|
|
2219
2391
|
|
|
2220
2392
|
---
|
|
2221
2393
|
|