@higinio/design-mcp 0.1.0 → 0.1.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/README.md +6 -3
- package/assets/celeste/design-doc.md +130 -15
- package/assets/celeste/framework.css +348 -0
- package/assets/celeste/styleguide.html +1292 -55
- package/assets/celeste/tailwind.css +4 -0
- package/assets/nocturna/design-doc.md +176 -37
- package/assets/nocturna/framework.css +329 -10
- package/assets/nocturna/styleguide.html +1213 -52
- package/assets/nocturna/tailwind.css +8 -2
- package/assets/nocturna/tokens.css +14 -8
- package/assets/nocturna/tokens.json +26 -1
- package/dist/slop.js +3 -3
- package/package.json +30 -8
|
@@ -291,6 +291,8 @@ html, body { overflow-x: clip; }
|
|
|
291
291
|
.field__help { font-size: var(--text-sm); color: var(--text-muted); }
|
|
292
292
|
.field__error { font-size: var(--text-sm); color: var(--danger-500); display: inline-flex; align-items: center; gap: 6px; }
|
|
293
293
|
.field__error svg { width: 14px; height: 14px; flex: none; }
|
|
294
|
+
/* Campo obligatorio (§10.4): asterisco decorativo; el input lleva required/aria-required */
|
|
295
|
+
.field--required .field__label::after { content: " *"; color: var(--danger-500); }
|
|
294
296
|
|
|
295
297
|
.input, .textarea, .select {
|
|
296
298
|
width: 100%; font-family: var(--font-body); font-size: var(--text-base);
|
|
@@ -402,6 +404,15 @@ html, body { overflow-x: clip; }
|
|
|
402
404
|
.checkbox input:checked ~ .checkbox__box svg { stroke-dashoffset: 0; }
|
|
403
405
|
.checkbox input:focus-visible ~ .checkbox__box { box-shadow: var(--ring); }
|
|
404
406
|
.checkbox input:disabled ~ * { opacity: .5; cursor: not-allowed; }
|
|
407
|
+
/* Estado indeterminate (§10.9): guion horizontal para "seleccionar todo" parcial */
|
|
408
|
+
.checkbox__box { position: relative; }
|
|
409
|
+
.checkbox input:indeterminate ~ .checkbox__box { background: var(--accent); border-color: var(--accent); }
|
|
410
|
+
.checkbox input:indeterminate ~ .checkbox__box svg { visibility: hidden; }
|
|
411
|
+
.checkbox input:indeterminate ~ .checkbox__box::after {
|
|
412
|
+
content: ""; position: absolute; top: 50%; left: 50%;
|
|
413
|
+
width: 10px; height: 2px;
|
|
414
|
+
background: var(--text-on-primary); transform: translate(-50%, -50%);
|
|
415
|
+
}
|
|
405
416
|
|
|
406
417
|
.radio__dot {
|
|
407
418
|
width: 20px; height: 20px; flex: none; display: grid; place-items: center;
|
|
@@ -504,6 +515,19 @@ html, body { overflow-x: clip; }
|
|
|
504
515
|
.avatar__dot--busy { background: var(--danger-500); }
|
|
505
516
|
.avatar__dot--away { background: var(--warning-500); }
|
|
506
517
|
|
|
518
|
+
/* AvatarGroup (§10.27): stack solapado con anillo de superficie */
|
|
519
|
+
.avatar-group { display: inline-flex; align-items: center; }
|
|
520
|
+
.avatar-group .avatar { border: 2px solid var(--surface); border-radius: var(--radius-full); }
|
|
521
|
+
.avatar-group .avatar + .avatar,
|
|
522
|
+
.avatar-group .avatar-group__more { margin-left: -8px; }
|
|
523
|
+
.avatar-group__more {
|
|
524
|
+
display: grid; place-items: center; flex: none;
|
|
525
|
+
width: 36px; height: 36px; border-radius: var(--radius-full);
|
|
526
|
+
border: 2px solid var(--surface);
|
|
527
|
+
background: var(--accent-soft-strong); color: var(--text-on-primary-solid);
|
|
528
|
+
font-family: var(--font-body); font-size: var(--text-xs); font-weight: var(--weight-semibold);
|
|
529
|
+
}
|
|
530
|
+
|
|
507
531
|
.divider { border: 0; border-top: var(--border-width) solid var(--border); margin: var(--space-4) 0; }
|
|
508
532
|
.divider--label {
|
|
509
533
|
display: flex; align-items: center; gap: 12px; border: 0; margin: var(--space-4) 0;
|
|
@@ -755,6 +779,30 @@ html, body { overflow-x: clip; }
|
|
|
755
779
|
.table tbody tr.is-selected { background: var(--accent-soft); }
|
|
756
780
|
.table .num, .table td.num, .table th.num { text-align: right; font-family: var(--font-mono); }
|
|
757
781
|
|
|
782
|
+
/* Variantes de tabla (§10.21): zebra, sticky header, orden y selección */
|
|
783
|
+
.table--zebra tbody tr:nth-child(even) { background: var(--surface-alt); }
|
|
784
|
+
.table--zebra tbody tr:nth-child(even):hover { background: var(--bg); }
|
|
785
|
+
.table--sticky thead th { position: sticky; top: 0; z-index: 1; }
|
|
786
|
+
.table tbody tr.row--selected,
|
|
787
|
+
.table tbody tr.row--selected:hover { background: var(--accent-soft); }
|
|
788
|
+
.table .col-select { width: 44px; text-align: center; }
|
|
789
|
+
.table .col-select .checkbox { display: inline-flex; justify-content: center; gap: 0; }
|
|
790
|
+
|
|
791
|
+
.th-sort {
|
|
792
|
+
display: inline-flex; align-items: center; gap: 6px; width: 100%;
|
|
793
|
+
border: 0; background: transparent; cursor: pointer;
|
|
794
|
+
font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; text-align: left;
|
|
795
|
+
}
|
|
796
|
+
.th-sort--num { justify-content: flex-end; }
|
|
797
|
+
.th-sort .sort-icon {
|
|
798
|
+
width: 14px; height: 14px; flex: none; opacity: .35;
|
|
799
|
+
transition: opacity var(--duration-fast) var(--ease-out),
|
|
800
|
+
transform var(--duration-base) var(--ease-out);
|
|
801
|
+
}
|
|
802
|
+
.table th[aria-sort="ascending"] .sort-icon,
|
|
803
|
+
.table th[aria-sort="descending"] .sort-icon { opacity: 1; color: var(--accent); }
|
|
804
|
+
.table th[aria-sort="descending"] .sort-icon { transform: rotate(180deg); }
|
|
805
|
+
|
|
758
806
|
.stat__label {
|
|
759
807
|
display: inline-flex; align-items: center; gap: 8px; margin-bottom: 8px;
|
|
760
808
|
font-size: var(--text-sm); color: var(--text-muted);
|
|
@@ -864,6 +912,298 @@ html, body { overflow-x: clip; }
|
|
|
864
912
|
border-radius: var(--radius-sm); padding: 1px 6px;
|
|
865
913
|
}
|
|
866
914
|
|
|
915
|
+
/* Combobox / Autocomplete (§10.28) */
|
|
916
|
+
.combobox { position: relative; }
|
|
917
|
+
.combobox__input {
|
|
918
|
+
width: 100%; height: var(--control-height-md); padding: 0 14px;
|
|
919
|
+
font-family: var(--font-body); font-size: var(--text-base);
|
|
920
|
+
color: var(--text-primary); background: var(--surface);
|
|
921
|
+
border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
|
|
922
|
+
transition: border-color var(--duration-fast) var(--ease-out),
|
|
923
|
+
box-shadow var(--duration-fast) var(--ease-out);
|
|
924
|
+
}
|
|
925
|
+
.combobox__input:hover:not(:disabled):not(:focus) { border-color: var(--text-disabled); }
|
|
926
|
+
.combobox__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
|
|
927
|
+
.combobox__input:disabled { background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed; }
|
|
928
|
+
.combobox__list {
|
|
929
|
+
position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 50;
|
|
930
|
+
max-height: 264px; overflow-y: auto; margin: 0; padding: 6px; list-style: none;
|
|
931
|
+
background: var(--surface); border: var(--border-width) solid var(--border);
|
|
932
|
+
border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
|
|
933
|
+
opacity: 0; transform: translateY(-4px); pointer-events: none;
|
|
934
|
+
transition: opacity var(--duration-base) var(--ease-out),
|
|
935
|
+
transform var(--duration-base) var(--ease-out);
|
|
936
|
+
}
|
|
937
|
+
.combobox.is-open .combobox__list { opacity: 1; transform: none; pointer-events: auto; }
|
|
938
|
+
.combobox__option {
|
|
939
|
+
display: flex; align-items: center; gap: 8px;
|
|
940
|
+
padding: 10px 12px; border-radius: var(--radius-sm);
|
|
941
|
+
font-size: var(--text-sm); color: var(--text-primary); cursor: pointer;
|
|
942
|
+
transition: background-color var(--duration-fast) var(--ease-out);
|
|
943
|
+
}
|
|
944
|
+
.combobox__option .combobox__check {
|
|
945
|
+
width: 16px; height: 16px; margin-left: auto; flex: none;
|
|
946
|
+
color: var(--accent); opacity: 0;
|
|
947
|
+
}
|
|
948
|
+
.combobox__option.is-active { background: var(--accent-soft); }
|
|
949
|
+
.combobox__option[aria-selected="true"] { color: var(--link); font-weight: var(--weight-medium); }
|
|
950
|
+
.combobox__option[aria-selected="true"] .combobox__check { opacity: 1; }
|
|
951
|
+
.combobox__empty { padding: 10px 12px; font-size: var(--text-sm); color: var(--text-muted); }
|
|
952
|
+
|
|
953
|
+
/* Búsqueda (§10.28) */
|
|
954
|
+
.search { position: relative; display: flex; align-items: center; }
|
|
955
|
+
.search__icon {
|
|
956
|
+
position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
|
|
957
|
+
width: 18px; height: 18px; color: var(--text-disabled); pointer-events: none;
|
|
958
|
+
}
|
|
959
|
+
.search__input {
|
|
960
|
+
width: 100%; height: var(--control-height-md); padding: 0 40px;
|
|
961
|
+
font-family: var(--font-body); font-size: var(--text-base);
|
|
962
|
+
color: var(--text-primary); background: var(--surface);
|
|
963
|
+
border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
|
|
964
|
+
transition: border-color var(--duration-fast) var(--ease-out),
|
|
965
|
+
box-shadow var(--duration-fast) var(--ease-out);
|
|
966
|
+
}
|
|
967
|
+
.search__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
|
|
968
|
+
.search__input:hover:not(:focus) { border-color: var(--text-disabled); }
|
|
969
|
+
.search__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
|
|
970
|
+
.search__clear {
|
|
971
|
+
position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
|
|
972
|
+
display: none; width: 32px; height: 32px; align-items: center; justify-content: center;
|
|
973
|
+
border: 0; border-radius: var(--radius-full); background: transparent;
|
|
974
|
+
color: var(--text-muted); cursor: pointer;
|
|
975
|
+
transition: background-color var(--duration-fast) var(--ease-out),
|
|
976
|
+
color var(--duration-fast) var(--ease-out);
|
|
977
|
+
}
|
|
978
|
+
.search__clear:hover { background: var(--surface-alt); color: var(--text-primary); }
|
|
979
|
+
.search__clear svg { width: 16px; height: 16px; }
|
|
980
|
+
.search__input:not(:placeholder-shown) ~ .search__clear { display: inline-flex; }
|
|
981
|
+
|
|
982
|
+
/* Drawer / Sheet (§10.29) */
|
|
983
|
+
.drawer {
|
|
984
|
+
position: fixed; inset: 0; z-index: 100;
|
|
985
|
+
visibility: hidden; pointer-events: none;
|
|
986
|
+
transition: visibility 0s linear var(--duration-base);
|
|
987
|
+
}
|
|
988
|
+
.drawer.is-open { visibility: visible; pointer-events: auto; transition-delay: 0s; }
|
|
989
|
+
.drawer__overlay {
|
|
990
|
+
position: absolute; inset: 0; background: var(--overlay);
|
|
991
|
+
opacity: 0; transition: opacity var(--duration-base) var(--ease-out);
|
|
992
|
+
}
|
|
993
|
+
.drawer.is-open .drawer__overlay { opacity: 1; }
|
|
994
|
+
.drawer__panel {
|
|
995
|
+
position: absolute; inset: 0 0 0 auto; width: min(400px, 100%);
|
|
996
|
+
display: flex; flex-direction: column; gap: var(--space-5);
|
|
997
|
+
padding: var(--card-padding); background: var(--surface);
|
|
998
|
+
box-shadow: var(--shadow-xl); overflow-y: auto; overscroll-behavior: contain;
|
|
999
|
+
transform: translateX(100%);
|
|
1000
|
+
transition: transform var(--duration-base) var(--ease-in);
|
|
1001
|
+
}
|
|
1002
|
+
.drawer.is-open .drawer__panel {
|
|
1003
|
+
transform: none;
|
|
1004
|
+
transition: transform var(--duration-slow) var(--ease-out);
|
|
1005
|
+
}
|
|
1006
|
+
.drawer--right .drawer__panel { inset: 0 0 0 auto; transform: translateX(100%); }
|
|
1007
|
+
.drawer--left .drawer__panel { inset: 0 auto 0 0; transform: translateX(-100%); }
|
|
1008
|
+
.drawer--bottom .drawer__panel {
|
|
1009
|
+
inset: auto 0 0 0; width: 100%; max-height: 85vh;
|
|
1010
|
+
border-radius: var(--radius-lg) var(--radius-lg) 0 0; transform: translateY(100%);
|
|
1011
|
+
}
|
|
1012
|
+
.drawer__header {
|
|
1013
|
+
display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
|
|
1014
|
+
}
|
|
1015
|
+
.drawer__title { font-size: var(--text-lg); font-weight: var(--weight-semibold); margin: 0; }
|
|
1016
|
+
.drawer__body { flex: 1; }
|
|
1017
|
+
.drawer__footer {
|
|
1018
|
+
display: flex; justify-content: flex-end; gap: var(--space-3); margin-top: auto;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/* Popover (§10.30) */
|
|
1022
|
+
.popover { position: relative; display: inline-block; }
|
|
1023
|
+
.popover__panel {
|
|
1024
|
+
position: absolute; top: calc(100% + 8px); left: 0; z-index: 60;
|
|
1025
|
+
width: max-content; max-width: 300px; padding: var(--space-4);
|
|
1026
|
+
background: var(--surface); border: var(--border-width) solid var(--border);
|
|
1027
|
+
border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
|
|
1028
|
+
transform-origin: top left; opacity: 0; transform: scale(.96); pointer-events: none;
|
|
1029
|
+
transition: opacity var(--duration-base) var(--ease-out),
|
|
1030
|
+
transform var(--duration-base) var(--ease-out);
|
|
1031
|
+
}
|
|
1032
|
+
.popover.is-open .popover__panel { opacity: 1; transform: none; pointer-events: auto; }
|
|
1033
|
+
.popover--right .popover__panel { left: auto; right: 0; transform-origin: top right; }
|
|
1034
|
+
|
|
1035
|
+
/* ButtonGroup (§10.31) */
|
|
1036
|
+
.btn-group { display: inline-flex; }
|
|
1037
|
+
.btn-group .btn { border-radius: 0; }
|
|
1038
|
+
.btn-group .btn:first-child {
|
|
1039
|
+
border-top-left-radius: var(--radius-md); border-bottom-left-radius: var(--radius-md);
|
|
1040
|
+
}
|
|
1041
|
+
.btn-group .btn:last-child {
|
|
1042
|
+
border-top-right-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md);
|
|
1043
|
+
}
|
|
1044
|
+
.btn-group .btn:not(:first-child) { margin-left: calc(var(--border-width) * -1); }
|
|
1045
|
+
.btn-group .btn:hover, .btn-group .btn:focus-visible { z-index: 1; }
|
|
1046
|
+
|
|
1047
|
+
/* DatePicker (§10.32) */
|
|
1048
|
+
.datepicker { position: relative; display: inline-block; }
|
|
1049
|
+
.datepicker__input {
|
|
1050
|
+
width: 100%; height: var(--control-height-md); padding: 0 40px 0 14px;
|
|
1051
|
+
font-family: var(--font-body); font-size: var(--text-base);
|
|
1052
|
+
color: var(--text-primary); background: var(--surface);
|
|
1053
|
+
border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
|
|
1054
|
+
transition: border-color var(--duration-fast) var(--ease-out),
|
|
1055
|
+
box-shadow var(--duration-fast) var(--ease-out);
|
|
1056
|
+
}
|
|
1057
|
+
.datepicker__input:hover:not(:disabled):not(:focus) { border-color: var(--text-disabled); }
|
|
1058
|
+
.datepicker__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
|
|
1059
|
+
.datepicker__input:disabled { background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed; }
|
|
1060
|
+
.datepicker__icon {
|
|
1061
|
+
position: absolute; right: 12px; top: calc(var(--control-height-md) / 2); transform: translateY(-50%);
|
|
1062
|
+
width: 18px; height: 18px; color: var(--text-muted); pointer-events: none;
|
|
1063
|
+
}
|
|
1064
|
+
.datepicker__calendar {
|
|
1065
|
+
position: absolute; top: calc(100% + 8px); left: 0; z-index: 60;
|
|
1066
|
+
width: max-content; padding: var(--space-4);
|
|
1067
|
+
background: var(--surface); border: var(--border-width) solid var(--border);
|
|
1068
|
+
border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
|
|
1069
|
+
transform-origin: top left; opacity: 0; transform: scale(.96); pointer-events: none;
|
|
1070
|
+
transition: opacity var(--duration-base) var(--ease-out),
|
|
1071
|
+
transform var(--duration-base) var(--ease-out);
|
|
1072
|
+
}
|
|
1073
|
+
.datepicker.is-open .datepicker__calendar { opacity: 1; transform: none; pointer-events: auto; }
|
|
1074
|
+
.datepicker--right .datepicker__calendar { left: auto; right: 0; transform-origin: top right; }
|
|
1075
|
+
|
|
1076
|
+
.calendar { width: 15.75rem; }
|
|
1077
|
+
.calendar__header {
|
|
1078
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
1079
|
+
gap: var(--space-2); margin-bottom: var(--space-3);
|
|
1080
|
+
}
|
|
1081
|
+
.calendar__title { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-primary); }
|
|
1082
|
+
.calendar__weekdays,
|
|
1083
|
+
.calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
|
|
1084
|
+
.calendar__weekdays { margin-bottom: 4px; }
|
|
1085
|
+
.calendar__weekday {
|
|
1086
|
+
display: flex; align-items: center; justify-content: center; height: 28px;
|
|
1087
|
+
font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--text-muted);
|
|
1088
|
+
}
|
|
1089
|
+
.calendar__day {
|
|
1090
|
+
display: flex; align-items: center; justify-content: center;
|
|
1091
|
+
width: 34px; height: 34px; margin: 0 auto; padding: 0;
|
|
1092
|
+
border: 0; border-radius: var(--radius-sm); background: transparent;
|
|
1093
|
+
font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-primary);
|
|
1094
|
+
cursor: pointer;
|
|
1095
|
+
transition: background-color var(--duration-fast) var(--ease-out),
|
|
1096
|
+
color var(--duration-fast) var(--ease-out);
|
|
1097
|
+
}
|
|
1098
|
+
.calendar__day:hover:not(:disabled):not(.calendar__day--selected) { background: var(--accent-soft); }
|
|
1099
|
+
.calendar__day--outside { color: var(--text-disabled); }
|
|
1100
|
+
.calendar__day--today { font-weight: var(--weight-semibold); box-shadow: inset 0 0 0 1px var(--border-strong); }
|
|
1101
|
+
.calendar__day--selected { background: var(--accent); color: var(--text-on-primary); font-weight: var(--weight-semibold); }
|
|
1102
|
+
.calendar__day:disabled { color: var(--text-disabled); cursor: not-allowed; }
|
|
1103
|
+
|
|
1104
|
+
/* FileUpload (§10.33) */
|
|
1105
|
+
.file-upload {
|
|
1106
|
+
border: 2px dashed var(--border-strong); border-radius: var(--radius-lg);
|
|
1107
|
+
background: var(--surface);
|
|
1108
|
+
transition: border-color var(--duration-fast) var(--ease-out),
|
|
1109
|
+
background-color var(--duration-fast) var(--ease-out);
|
|
1110
|
+
}
|
|
1111
|
+
.file-upload.is-dragover { border-color: var(--accent); background: var(--accent-soft); }
|
|
1112
|
+
.file-upload__input {
|
|
1113
|
+
position: absolute; width: 1px; height: 1px; margin: -1px;
|
|
1114
|
+
clip-path: inset(50%); overflow: hidden; white-space: nowrap;
|
|
1115
|
+
}
|
|
1116
|
+
.file-upload__label {
|
|
1117
|
+
display: flex; flex-direction: column; align-items: center; text-align: center;
|
|
1118
|
+
gap: var(--space-2); padding: var(--space-8) var(--space-6); cursor: pointer;
|
|
1119
|
+
}
|
|
1120
|
+
.file-upload__label > svg { width: 32px; height: 32px; color: var(--text-muted); }
|
|
1121
|
+
.file-upload__title { font-size: var(--text-sm); color: var(--text-secondary); }
|
|
1122
|
+
.file-upload__hint { font-size: var(--text-xs); color: var(--text-muted); }
|
|
1123
|
+
.file-upload__button {
|
|
1124
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1125
|
+
height: var(--control-height-sm); padding: 0 16px; margin-top: var(--space-1);
|
|
1126
|
+
border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-md);
|
|
1127
|
+
font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-primary);
|
|
1128
|
+
background: var(--surface);
|
|
1129
|
+
transition: background-color var(--duration-fast) var(--ease-out);
|
|
1130
|
+
}
|
|
1131
|
+
.file-upload__label:hover .file-upload__button { background: var(--bg); }
|
|
1132
|
+
.file-upload__list { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
|
|
1133
|
+
.file-upload__item {
|
|
1134
|
+
display: flex; align-items: center; gap: var(--space-3);
|
|
1135
|
+
padding: var(--space-3); border: var(--border-width) solid var(--border);
|
|
1136
|
+
border-radius: var(--radius-md); background: var(--surface);
|
|
1137
|
+
}
|
|
1138
|
+
.file-upload__icon { width: 20px; height: 20px; color: var(--text-muted); flex: none; }
|
|
1139
|
+
.file-upload__meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1; }
|
|
1140
|
+
.file-upload__name {
|
|
1141
|
+
font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-primary);
|
|
1142
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
1143
|
+
}
|
|
1144
|
+
.file-upload__size { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); color: var(--text-muted); }
|
|
1145
|
+
.file-upload__size svg { width: 12px; height: 12px; flex: none; }
|
|
1146
|
+
.file-upload__meta .progress { margin-top: 2px; }
|
|
1147
|
+
.file-upload__remove {
|
|
1148
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1149
|
+
width: 32px; height: 32px; flex: none; border: 0; border-radius: var(--radius-full);
|
|
1150
|
+
background: transparent; color: var(--text-muted); cursor: pointer;
|
|
1151
|
+
transition: background-color var(--duration-fast) var(--ease-out),
|
|
1152
|
+
color var(--duration-fast) var(--ease-out);
|
|
1153
|
+
}
|
|
1154
|
+
.file-upload__remove:hover { background: var(--surface-alt); color: var(--text-primary); }
|
|
1155
|
+
.file-upload__remove svg { width: 16px; height: 16px; }
|
|
1156
|
+
.file-upload__item--error { border-color: var(--danger-500); }
|
|
1157
|
+
.file-upload__item--error .file-upload__icon,
|
|
1158
|
+
.file-upload__item--error .file-upload__size { color: var(--danger-text); }
|
|
1159
|
+
|
|
1160
|
+
/* Stepper / Wizard (§10.34) */
|
|
1161
|
+
.stepper { display: flex; list-style: none; margin: 0; padding: 0; }
|
|
1162
|
+
.step {
|
|
1163
|
+
position: relative; flex: 1;
|
|
1164
|
+
display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-2);
|
|
1165
|
+
}
|
|
1166
|
+
.step__marker {
|
|
1167
|
+
position: relative; z-index: 1;
|
|
1168
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1169
|
+
width: 32px; height: 32px; flex: none; border-radius: var(--radius-full);
|
|
1170
|
+
border: 2px solid var(--border-strong); background: var(--surface);
|
|
1171
|
+
font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-muted);
|
|
1172
|
+
}
|
|
1173
|
+
.step__marker svg { width: 16px; height: 16px; }
|
|
1174
|
+
.step__label { font-size: var(--text-sm); color: var(--text-secondary); }
|
|
1175
|
+
.step__connector {
|
|
1176
|
+
position: absolute; top: 16px; z-index: 0; left: 50%; right: -50%;
|
|
1177
|
+
height: 2px; margin: 0 20px; background: var(--border);
|
|
1178
|
+
}
|
|
1179
|
+
.step--complete .step__marker { background: var(--accent); border-color: var(--accent); color: var(--text-on-primary); }
|
|
1180
|
+
.step--complete .step__label { color: var(--text-primary); }
|
|
1181
|
+
.step--complete .step__connector { background: var(--accent); }
|
|
1182
|
+
.step--current .step__marker { border-color: var(--accent); color: var(--accent); }
|
|
1183
|
+
.step--current .step__label { color: var(--text-primary); font-weight: var(--weight-semibold); }
|
|
1184
|
+
.stepper--vertical { flex-direction: column; align-items: stretch; }
|
|
1185
|
+
.stepper--vertical .step {
|
|
1186
|
+
flex-direction: row; align-items: flex-start; text-align: left;
|
|
1187
|
+
gap: var(--space-3); padding-bottom: var(--space-6);
|
|
1188
|
+
}
|
|
1189
|
+
.stepper--vertical .step:last-child { padding-bottom: 0; }
|
|
1190
|
+
.stepper--vertical .step__connector {
|
|
1191
|
+
top: 36px; bottom: -4px; left: 15px; right: auto;
|
|
1192
|
+
width: 2px; height: auto; margin: 0;
|
|
1193
|
+
}
|
|
1194
|
+
.stepper--vertical .step__label { padding-top: 5px; }
|
|
1195
|
+
|
|
1196
|
+
/* Kbd (§10.35) */
|
|
1197
|
+
.kbd {
|
|
1198
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
1199
|
+
min-width: 20px; height: 20px; padding: 0 6px;
|
|
1200
|
+
font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1;
|
|
1201
|
+
color: var(--text-secondary); background: var(--surface);
|
|
1202
|
+
border: var(--border-width) solid var(--border-strong);
|
|
1203
|
+
border-radius: var(--radius-sm); box-shadow: var(--shadow-xs);
|
|
1204
|
+
}
|
|
1205
|
+
.kbd-combo { display: inline-flex; align-items: center; gap: 4px; color: var(--text-muted); font-size: var(--text-xs); }
|
|
1206
|
+
|
|
867
1207
|
.u-visually-hidden {
|
|
868
1208
|
position: absolute; width: 1px; height: 1px; margin: -1px;
|
|
869
1209
|
clip-path: inset(50%); overflow: hidden; white-space: nowrap;
|
|
@@ -1115,6 +1455,10 @@ html, body { overflow-x: clip; }
|
|
|
1115
1455
|
<symbol id="i-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></symbol>
|
|
1116
1456
|
<symbol id="i-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h16"/><path d="M4 12h16"/><path d="M4 18h16"/></symbol>
|
|
1117
1457
|
<symbol id="i-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/></symbol>
|
|
1458
|
+
<symbol id="i-upload" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m17 8-5-5-5 5"/><path d="M12 3v12"/></symbol>
|
|
1459
|
+
<symbol id="i-file" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></symbol>
|
|
1460
|
+
<symbol id="i-calendar" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></symbol>
|
|
1461
|
+
<symbol id="i-arrow-up" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 12 7-7 7 7"/><path d="M12 19V5"/></symbol>
|
|
1118
1462
|
</defs>
|
|
1119
1463
|
</svg>
|
|
1120
1464
|
|
|
@@ -1160,6 +1504,7 @@ html, body { overflow-x: clip; }
|
|
|
1160
1504
|
<a href="#comp-switch">Switch</a>
|
|
1161
1505
|
<a href="#comp-badge-tag">Badge y Tag</a>
|
|
1162
1506
|
<a href="#comp-avatar">Avatar</a>
|
|
1507
|
+
<a href="#comp-avatar-group">AvatarGroup</a>
|
|
1163
1508
|
<a href="#comp-divider">Divider</a>
|
|
1164
1509
|
<a href="#comp-accordion">Accordion</a>
|
|
1165
1510
|
<a href="#comp-tooltip">Tooltip</a>
|
|
@@ -1174,6 +1519,14 @@ html, body { overflow-x: clip; }
|
|
|
1174
1519
|
<a href="#comp-navegacion">Navegación</a>
|
|
1175
1520
|
<a href="#comp-skeleton">Skeleton y EmptyState</a>
|
|
1176
1521
|
<a href="#comp-card">Card, Link y Code</a>
|
|
1522
|
+
<a href="#comp-combobox">Combobox y búsqueda</a>
|
|
1523
|
+
<a href="#comp-drawer">Drawer / Sheet</a>
|
|
1524
|
+
<a href="#comp-popover">Popover</a>
|
|
1525
|
+
<a href="#comp-button-group">ButtonGroup</a>
|
|
1526
|
+
<a href="#comp-datepicker">DatePicker</a>
|
|
1527
|
+
<a href="#comp-file-upload">FileUpload</a>
|
|
1528
|
+
<a href="#comp-stepper">Stepper / Wizard</a>
|
|
1529
|
+
<a href="#comp-kbd">Kbd</a>
|
|
1177
1530
|
</div>
|
|
1178
1531
|
<div class="ds-nav__group">Recursos</div>
|
|
1179
1532
|
<a href="#motion">Motion</a>
|
|
@@ -1415,7 +1768,7 @@ html, body { overflow-x: clip; }
|
|
|
1415
1768
|
<section id="componentes">
|
|
1416
1769
|
<p class="ds-eyebrow">Biblioteca</p>
|
|
1417
1770
|
<h2>Componentes</h2>
|
|
1418
|
-
<p class="ds-lead">Los
|
|
1771
|
+
<p class="ds-lead">Los 35 componentes del sistema, renderizados en vivo con las clases del framework <span class="u-mono">celeste-clasica.css</span>. Cada bloque incluye su código de uso.</p>
|
|
1419
1772
|
|
|
1420
1773
|
<!-- Botones -->
|
|
1421
1774
|
<div class="ds-component" id="comp-botones">
|
|
@@ -1499,8 +1852,12 @@ html, body { overflow-x: clip; }
|
|
|
1499
1852
|
<!-- Input -->
|
|
1500
1853
|
<div class="ds-component" id="comp-input">
|
|
1501
1854
|
<h3>Input</h3>
|
|
1502
|
-
<p class="ds-spec">Altura 44 px · label siempre visible (nunca placeholder como label) · focus con borde <span class="u-mono">--accent</span> + ring.</p>
|
|
1855
|
+
<p class="ds-spec">Altura 44 px · label siempre visible (nunca placeholder como label) · focus con borde <span class="u-mono">--accent</span> + ring · obligatorio con <span class="u-mono">.field--required</span> (asterisco <span class="u-mono">--danger</span> + <span class="u-mono">required/aria-required</span>).</p>
|
|
1503
1856
|
<div class="ds-demo ds-demo--col" style="max-width:420px">
|
|
1857
|
+
<div class="field field--required">
|
|
1858
|
+
<label class="field__label" for="demo-input-req">Nombre completo</label>
|
|
1859
|
+
<input class="input" id="demo-input-req" type="text" required aria-required="true" autocomplete="name" placeholder="Tu nombre">
|
|
1860
|
+
</div>
|
|
1504
1861
|
<div class="field">
|
|
1505
1862
|
<label class="field__label" for="demo-input-1">Correo electrónico</label>
|
|
1506
1863
|
<input class="input" id="demo-input-1" type="email" placeholder="tu@correo.com">
|
|
@@ -1535,6 +1892,12 @@ html, body { overflow-x: clip; }
|
|
|
1535
1892
|
<span class="field__help">Nunca compartiremos tu correo.</span>
|
|
1536
1893
|
</div>
|
|
1537
1894
|
|
|
1895
|
+
<!-- Obligatorio: .field--required en el .field + required/aria-required en el input -->
|
|
1896
|
+
<div class="field field--required">
|
|
1897
|
+
<label class="field__label" for="nombre">Nombre completo</label>
|
|
1898
|
+
<input class="input" id="nombre" required aria-required="true">
|
|
1899
|
+
</div>
|
|
1900
|
+
|
|
1538
1901
|
<!-- Estados: input--error (+ .field__error) · input--success · disabled
|
|
1539
1902
|
Icono leading: envolver en .input-icon --></code></pre>
|
|
1540
1903
|
</div>
|
|
@@ -1648,10 +2011,11 @@ html, body { overflow-x: clip; }
|
|
|
1648
2011
|
<!-- Checkbox y Radio -->
|
|
1649
2012
|
<div class="ds-component" id="comp-checkbox-radio">
|
|
1650
2013
|
<h3>Checkbox y Radio</h3>
|
|
1651
|
-
<p class="ds-spec">20 px · borde 2 px · check que se dibuja con <span class="u-mono">ease-spring</span> · label clicable con gap 10 px.</p>
|
|
2014
|
+
<p class="ds-spec">20 px · borde 2 px · check que se dibuja con <span class="u-mono">ease-spring</span> · label clicable con gap 10 px · estado <span class="u-mono">indeterminate</span> (guion) para «seleccionar todo» parcial.</p>
|
|
1652
2015
|
<div class="ds-demo">
|
|
1653
2016
|
<label class="checkbox"><input type="checkbox" checked><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span>Recibir novedades</label>
|
|
1654
2017
|
<label class="checkbox"><input type="checkbox"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span>Recordarme</label>
|
|
2018
|
+
<label class="checkbox"><input type="checkbox" id="demoIndeterminate"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span>Seleccionar todo (parcial)</label>
|
|
1655
2019
|
<label class="checkbox"><input type="checkbox" disabled><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span>Deshabilitado</label>
|
|
1656
2020
|
</div>
|
|
1657
2021
|
<div class="ds-demo" role="radiogroup" aria-label="Plan">
|
|
@@ -1673,7 +2037,10 @@ html, body { overflow-x: clip; }
|
|
|
1673
2037
|
<input type="radio" name="plan" checked>
|
|
1674
2038
|
<span class="radio__dot"></span>
|
|
1675
2039
|
Plan mensual
|
|
1676
|
-
</label>
|
|
2040
|
+
</label>
|
|
2041
|
+
|
|
2042
|
+
<!-- Indeterminate: propiedad del DOM, no atributo HTML -->
|
|
2043
|
+
<!-- checkbox.indeterminate = true (guion horizontal) --></code></pre>
|
|
1677
2044
|
</div>
|
|
1678
2045
|
</details>
|
|
1679
2046
|
</div>
|
|
@@ -1756,6 +2123,33 @@ html, body { overflow-x: clip; }
|
|
|
1756
2123
|
</details>
|
|
1757
2124
|
</div>
|
|
1758
2125
|
|
|
2126
|
+
<!-- AvatarGroup -->
|
|
2127
|
+
<div class="ds-component" id="comp-avatar-group">
|
|
2128
|
+
<h3>AvatarGroup</h3>
|
|
2129
|
+
<p class="ds-spec">Stack de avatares solapados (<span class="u-mono">-8px</span>) con anillo 2 px de <span class="u-mono">--surface</span> que los separa · <span class="u-mono">avatar-group__more</span> para el +N de overflow.</p>
|
|
2130
|
+
<div class="ds-demo">
|
|
2131
|
+
<div class="avatar-group">
|
|
2132
|
+
<span class="avatar"><span class="avatar__initials">HS</span></span>
|
|
2133
|
+
<span class="avatar"><span class="avatar__initials">MG</span></span>
|
|
2134
|
+
<span class="avatar"><span class="avatar__initials">AL</span></span>
|
|
2135
|
+
<span class="avatar"><span class="avatar__initials">RD</span></span>
|
|
2136
|
+
<span class="avatar-group__more">+3</span>
|
|
2137
|
+
</div>
|
|
2138
|
+
</div>
|
|
2139
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2140
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2141
|
+
<pre class="ds-pre"><code><div class="avatar-group">
|
|
2142
|
+
<span class="avatar"><span class="avatar__initials">HS</span></span>
|
|
2143
|
+
<span class="avatar"><span class="avatar__initials">MG</span></span>
|
|
2144
|
+
<span class="avatar"><span class="avatar__initials">AL</span></span>
|
|
2145
|
+
<span class="avatar"><span class="avatar__initials">RD</span></span>
|
|
2146
|
+
<span class="avatar-group__more">+3</span>
|
|
2147
|
+
</div>
|
|
2148
|
+
<!-- Solape -8px · cada avatar con anillo 2px de --surface --></code></pre>
|
|
2149
|
+
</div>
|
|
2150
|
+
</details>
|
|
2151
|
+
</div>
|
|
2152
|
+
|
|
1759
2153
|
<!-- Divider -->
|
|
1760
2154
|
<div class="ds-component" id="comp-divider">
|
|
1761
2155
|
<h3>Divider</h3>
|
|
@@ -1936,28 +2330,32 @@ html, body { overflow-x: clip; }
|
|
|
1936
2330
|
<!-- Modal -->
|
|
1937
2331
|
<div class="ds-component" id="comp-modal">
|
|
1938
2332
|
<h3>Modal</h3>
|
|
1939
|
-
<p class="ds-spec">
|
|
2333
|
+
<p class="ds-spec"><span class="u-mono">role="dialog"</span> · <span class="u-mono">aria-modal</span> · <span class="u-mono">aria-labelledby</span> + <span class="u-mono">aria-describedby</span> · al abrir el foco entra al panel, queda atrapado (Tab/Shift+Tab ciclan) y vuelve al disparador al cerrar · Esc y click en overlay cierran, salvo flujos destructivos (el de confirmación no cierra por overlay).</p>
|
|
1940
2334
|
<div class="ds-demo">
|
|
1941
2335
|
<button class="btn btn--secondary" data-modal-open="demoModal">Abrir confirmación</button>
|
|
1942
2336
|
<button class="btn btn--secondary" data-modal-open="demoModalLg">Abrir formulario</button>
|
|
1943
2337
|
</div>
|
|
1944
2338
|
<details class="ds-code"><summary>Ver código</summary>
|
|
1945
2339
|
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
1946
|
-
<pre class="ds-pre"><code><div class="modal" id="miModal" role="dialog" aria-modal="true"
|
|
2340
|
+
<pre class="ds-pre"><code><div class="modal" id="miModal" role="dialog" aria-modal="true"
|
|
2341
|
+
aria-labelledby="miModalTitulo" aria-describedby="miModalDesc">
|
|
2342
|
+
<!-- overlay sin data-modal-close en flujos destructivos -->
|
|
1947
2343
|
<div class="modal__overlay" data-modal-close></div>
|
|
1948
|
-
<div class="modal__panel">
|
|
2344
|
+
<div class="modal__panel" tabindex="-1">
|
|
1949
2345
|
<div class="modal__header">
|
|
1950
2346
|
<h4 class="modal__title" id="miModalTitulo">¿Eliminar proyecto?</h4>
|
|
1951
2347
|
<button class="icon-btn icon-btn--ghost" data-modal-close aria-label="Cerrar">…x…</button>
|
|
1952
2348
|
</div>
|
|
1953
|
-
<p>Esta acción no se puede deshacer.</p>
|
|
2349
|
+
<p id="miModalDesc">Esta acción no se puede deshacer.</p>
|
|
1954
2350
|
<div class="modal__footer">
|
|
1955
2351
|
<button class="btn btn--secondary" data-modal-close>Cancelar</button>
|
|
1956
2352
|
<button class="btn btn--danger">Eliminar</button>
|
|
1957
2353
|
</div>
|
|
1958
2354
|
</div>
|
|
1959
2355
|
</div>
|
|
1960
|
-
<!-- Panel ancho: modal__panel--lg (640px) -->
|
|
2356
|
+
<!-- Panel ancho: modal__panel--lg (640px) -->
|
|
2357
|
+
<!-- JS: al abrir guarda el disparador y enfoca el panel; Tab/Shift+Tab
|
|
2358
|
+
atrapados dentro; al cerrar (Esc, ×, Cancelar) el foco vuelve al disparador --></code></pre>
|
|
1961
2359
|
</div>
|
|
1962
2360
|
</details>
|
|
1963
2361
|
</div>
|
|
@@ -1996,27 +2394,77 @@ html, body { overflow-x: clip; }
|
|
|
1996
2394
|
<!-- Tabla -->
|
|
1997
2395
|
<div class="ds-component" id="comp-tabla">
|
|
1998
2396
|
<h3>Tabla</h3>
|
|
1999
|
-
<p class="ds-spec">Header uppercase <span class="u-mono">+0.04em</span> · filas 52 px · numéricos a la derecha con <span class="u-mono">tabular-nums</span> ·
|
|
2000
|
-
<div class="ds-demo ds-demo--col" style="padding:0
|
|
2001
|
-
<
|
|
2002
|
-
<
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2397
|
+
<p class="ds-spec">Header uppercase <span class="u-mono">+0.04em</span> · filas 52 px · numéricos a la derecha con <span class="u-mono">tabular-nums</span>. Variantes: <span class="u-mono">.table--zebra</span> · <span class="u-mono">.table--sticky</span> (header fijo) · columna ordenable con <span class="u-mono">aria-sort</span> · selección con <span class="u-mono">.row--selected</span> y «seleccionar todo» indeterminate.</p>
|
|
2398
|
+
<div class="ds-demo ds-demo--col" style="padding:0">
|
|
2399
|
+
<div style="max-height:264px;overflow:auto;width:100%">
|
|
2400
|
+
<table class="table table--zebra table--sticky" id="demoTable">
|
|
2401
|
+
<thead>
|
|
2402
|
+
<tr>
|
|
2403
|
+
<th class="col-select" scope="col">
|
|
2404
|
+
<label class="checkbox"><input type="checkbox" id="demoSelectAll" aria-label="Seleccionar todas las filas"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span></label>
|
|
2405
|
+
</th>
|
|
2406
|
+
<th scope="col">Cliente</th>
|
|
2407
|
+
<th scope="col">Estado</th>
|
|
2408
|
+
<th class="num" scope="col" aria-sort="none">
|
|
2409
|
+
<button type="button" class="th-sort th-sort--num" data-sort="monto">Monto<svg class="sort-icon" aria-hidden="true"><use href="#i-arrow-up"/></svg></button>
|
|
2410
|
+
</th>
|
|
2411
|
+
</tr>
|
|
2412
|
+
</thead>
|
|
2413
|
+
<tbody>
|
|
2414
|
+
<tr>
|
|
2415
|
+
<td class="col-select"><label class="checkbox"><input type="checkbox" class="js-row-select" aria-label="Seleccionar Constructora Delta"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span></label></td>
|
|
2416
|
+
<td>Constructora Delta</td>
|
|
2417
|
+
<td><span class="badge badge--success"><svg><use href="#i-circle-check"/></svg>Activo</span></td>
|
|
2418
|
+
<td class="num" data-monto="48200">$ 48,200.00</td>
|
|
2419
|
+
</tr>
|
|
2420
|
+
<tr class="row--selected">
|
|
2421
|
+
<td class="col-select"><label class="checkbox"><input type="checkbox" class="js-row-select" checked aria-label="Seleccionar Grupo Andrade"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span></label></td>
|
|
2422
|
+
<td>Grupo Andrade</td>
|
|
2423
|
+
<td><span class="badge badge--warning"><svg><use href="#i-triangle-alert"/></svg>Pendiente</span></td>
|
|
2424
|
+
<td class="num" data-monto="9850">$ 9,850.00</td>
|
|
2425
|
+
</tr>
|
|
2426
|
+
<tr>
|
|
2427
|
+
<td class="col-select"><label class="checkbox"><input type="checkbox" class="js-row-select" aria-label="Seleccionar Studio Nébula"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span></label></td>
|
|
2428
|
+
<td>Studio Nébula</td>
|
|
2429
|
+
<td><span class="badge badge--success"><svg><use href="#i-circle-check"/></svg>Activo</span></td>
|
|
2430
|
+
<td class="num" data-monto="132400">$ 132,400.00</td>
|
|
2431
|
+
</tr>
|
|
2432
|
+
<tr>
|
|
2433
|
+
<td class="col-select"><label class="checkbox"><input type="checkbox" class="js-row-select" aria-label="Seleccionar Farmacias Luna"><span class="checkbox__box"><svg viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg></span></label></td>
|
|
2434
|
+
<td>Farmacias Luna</td>
|
|
2435
|
+
<td><span class="badge badge--danger"><svg><use href="#i-circle-alert"/></svg>Vencido</span></td>
|
|
2436
|
+
<td class="num" data-monto="1120">$ 1,120.00</td>
|
|
2437
|
+
</tr>
|
|
2438
|
+
</tbody>
|
|
2439
|
+
</table>
|
|
2440
|
+
</div>
|
|
2010
2441
|
</div>
|
|
2011
2442
|
<details class="ds-code"><summary>Ver código</summary>
|
|
2012
2443
|
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2013
|
-
<pre class="ds-pre"><code><table class="table">
|
|
2014
|
-
<thead>
|
|
2444
|
+
<pre class="ds-pre"><code><table class="table table--zebra table--sticky">
|
|
2445
|
+
<thead>
|
|
2446
|
+
<tr>
|
|
2447
|
+
<th class="col-select" scope="col">
|
|
2448
|
+
<label class="checkbox"><input type="checkbox" aria-label="Seleccionar todo">
|
|
2449
|
+
<span class="checkbox__box"><svg>…check…</svg></span></label>
|
|
2450
|
+
</th>
|
|
2451
|
+
<th scope="col">Cliente</th>
|
|
2452
|
+
<th class="num" scope="col" aria-sort="none">
|
|
2453
|
+
<button class="th-sort th-sort--num" data-sort="monto">
|
|
2454
|
+
Monto<svg class="sort-icon" aria-hidden="true">…</svg></button>
|
|
2455
|
+
</th>
|
|
2456
|
+
</tr>
|
|
2457
|
+
</thead>
|
|
2015
2458
|
<tbody>
|
|
2016
|
-
<tr
|
|
2017
|
-
|
|
2459
|
+
<tr class="row--selected">
|
|
2460
|
+
<td class="col-select"><label class="checkbox"><input type="checkbox" checked
|
|
2461
|
+
aria-label="Seleccionar Grupo Andrade">…</label></td>
|
|
2462
|
+
<td>Grupo Andrade</td><td class="num" data-monto="9850">$ 9,850.00</td>
|
|
2463
|
+
</tr>
|
|
2018
2464
|
</tbody>
|
|
2019
|
-
</table>
|
|
2465
|
+
</table>
|
|
2466
|
+
<!-- JS: click en .th-sort alterna aria-sort asc/desc y reordena tbody;
|
|
2467
|
+
el checkbox del header pasa a indeterminate con selección parcial --></code></pre>
|
|
2020
2468
|
</div>
|
|
2021
2469
|
</details>
|
|
2022
2470
|
</div>
|
|
@@ -2222,6 +2670,366 @@ html, body { overflow-x: clip; }
|
|
|
2222
2670
|
</div>
|
|
2223
2671
|
</details>
|
|
2224
2672
|
</div>
|
|
2673
|
+
|
|
2674
|
+
<!-- Combobox / Autocomplete y Búsqueda -->
|
|
2675
|
+
<div class="ds-component" id="comp-combobox">
|
|
2676
|
+
<h3>Combobox y búsqueda</h3>
|
|
2677
|
+
<p class="ds-spec"><span class="u-mono">role="combobox"</span> · <span class="u-mono">aria-expanded</span> + <span class="u-mono">aria-controls</span> + <span class="u-mono">aria-activedescendant</span> · lista <span class="u-mono">role="listbox"</span>, opciones <span class="u-mono">role="option"</span> · ↑/↓ mueven, Enter elige, Esc cierra, Home/End a extremos. La búsqueda se limpia con la ×.</p>
|
|
2678
|
+
<div class="ds-demo ds-demo--col" style="max-width:420px">
|
|
2679
|
+
<div class="field">
|
|
2680
|
+
<label class="field__label" for="cbxInput">Ciudad</label>
|
|
2681
|
+
<div class="combobox" id="cbx">
|
|
2682
|
+
<input class="combobox__input" id="cbxInput" type="text" role="combobox" aria-expanded="false" aria-controls="cbxList" aria-autocomplete="list" autocomplete="off" spellcheck="false" placeholder="Escribe para filtrar…">
|
|
2683
|
+
<ul class="combobox__list" id="cbxList" role="listbox" aria-label="Ciudades"></ul>
|
|
2684
|
+
</div>
|
|
2685
|
+
</div>
|
|
2686
|
+
<div class="field">
|
|
2687
|
+
<label class="field__label" for="searchInput">Buscar</label>
|
|
2688
|
+
<div class="search">
|
|
2689
|
+
<svg class="search__icon" aria-hidden="true"><use href="#i-search"/></svg>
|
|
2690
|
+
<input class="search__input" id="searchInput" type="search" autocomplete="off" spellcheck="false" placeholder="Buscar proyectos…">
|
|
2691
|
+
<button class="search__clear" type="button" aria-label="Limpiar"><svg><use href="#i-x"/></svg></button>
|
|
2692
|
+
</div>
|
|
2693
|
+
</div>
|
|
2694
|
+
</div>
|
|
2695
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2696
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2697
|
+
<pre class="ds-pre"><code><div class="combobox">
|
|
2698
|
+
<input class="combobox__input" type="text" role="combobox"
|
|
2699
|
+
aria-expanded="false" aria-controls="lista" aria-autocomplete="list"
|
|
2700
|
+
aria-activedescendant="opt-0" autocomplete="off">
|
|
2701
|
+
<ul class="combobox__list" id="lista" role="listbox" aria-label="Ciudades">
|
|
2702
|
+
<li class="combobox__option is-active" role="option" id="opt-0"
|
|
2703
|
+
aria-selected="false">Guadalajara</li>
|
|
2704
|
+
<li class="combobox__option" role="option" id="opt-1"
|
|
2705
|
+
aria-selected="true">Monterrey
|
|
2706
|
+
<svg class="combobox__check">…check…</svg></li>
|
|
2707
|
+
</ul>
|
|
2708
|
+
</div>
|
|
2709
|
+
|
|
2710
|
+
<div class="search">
|
|
2711
|
+
<svg class="search__icon" aria-hidden="true">…lupa…</svg>
|
|
2712
|
+
<input class="search__input" type="search" placeholder="Buscar…">
|
|
2713
|
+
<button class="search__clear" aria-label="Limpiar">…x…</button>
|
|
2714
|
+
</div></code></pre>
|
|
2715
|
+
</div>
|
|
2716
|
+
</details>
|
|
2717
|
+
</div>
|
|
2718
|
+
|
|
2719
|
+
<!-- Drawer / Sheet -->
|
|
2720
|
+
<div class="ds-component" id="comp-drawer">
|
|
2721
|
+
<h3>Drawer / Sheet</h3>
|
|
2722
|
+
<p class="ds-spec"><span class="u-mono">role="dialog"</span> · <span class="u-mono">aria-modal</span> · foco atrapado y devuelto al disparador (patrón del Modal) · <span class="u-mono">overscroll-behavior: contain</span> · entra deslizando desde el borde y sale más corto · Esc y click en overlay cierran. Variantes <span class="u-mono">--right</span> (default), <span class="u-mono">--left</span>, <span class="u-mono">--bottom</span>.</p>
|
|
2723
|
+
<div class="ds-demo">
|
|
2724
|
+
<button class="btn btn--secondary" data-drawer-open="demoDrawer">Abrir panel de filtros</button>
|
|
2725
|
+
</div>
|
|
2726
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2727
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2728
|
+
<pre class="ds-pre"><code><div class="drawer drawer--right" id="miDrawer" role="dialog"
|
|
2729
|
+
aria-modal="true" aria-labelledby="miDrawerTitulo">
|
|
2730
|
+
<div class="drawer__overlay" data-drawer-close></div>
|
|
2731
|
+
<div class="drawer__panel" tabindex="-1">
|
|
2732
|
+
<div class="drawer__header">
|
|
2733
|
+
<h4 class="drawer__title" id="miDrawerTitulo">Filtrar proyectos</h4>
|
|
2734
|
+
<button class="icon-btn icon-btn--ghost" data-drawer-close aria-label="Cerrar">…x…</button>
|
|
2735
|
+
</div>
|
|
2736
|
+
<!-- campos… -->
|
|
2737
|
+
<div class="drawer__footer">
|
|
2738
|
+
<button class="btn btn--secondary" data-drawer-close>Cancelar</button>
|
|
2739
|
+
<button class="btn btn--primary" data-drawer-close>Aplicar</button>
|
|
2740
|
+
</div>
|
|
2741
|
+
</div>
|
|
2742
|
+
</div></code></pre>
|
|
2743
|
+
</div>
|
|
2744
|
+
</details>
|
|
2745
|
+
</div>
|
|
2746
|
+
|
|
2747
|
+
<!-- Popover -->
|
|
2748
|
+
<div class="ds-component" id="comp-popover">
|
|
2749
|
+
<h3>Popover</h3>
|
|
2750
|
+
<p class="ds-spec">Se abre por <strong>click</strong> (no hover, a diferencia del tooltip) y lleva contenido interactivo · trigger <span class="u-mono">aria-haspopup="dialog"</span> + <span class="u-mono">aria-expanded</span> · panel <span class="u-mono">role="dialog"</span> · aparece desde el trigger (fade + scale 0.96→1) · Esc y click fuera cierran.</p>
|
|
2751
|
+
<div class="ds-demo">
|
|
2752
|
+
<div class="popover" id="demoPopover">
|
|
2753
|
+
<button class="btn btn--secondary popover__trigger" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="demoPopoverPanel"><svg><use href="#i-info"/></svg>Detalles del plan</button>
|
|
2754
|
+
<div class="popover__panel" id="demoPopoverPanel" role="dialog" aria-label="Detalles del plan" tabindex="-1">
|
|
2755
|
+
<p style="margin:0 0 6px;font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--text-primary)">Plan Estudio</p>
|
|
2756
|
+
<p style="margin:0 0 12px;font-size:var(--text-sm);color:var(--text-secondary)">Incluye 12 tableros, 3 integraciones y respaldo diario. Puedes cambiar de plan cuando quieras.</p>
|
|
2757
|
+
<a class="link" href="#comp-popover">Ver comparación de planes</a>
|
|
2758
|
+
</div>
|
|
2759
|
+
</div>
|
|
2760
|
+
</div>
|
|
2761
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2762
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2763
|
+
<pre class="ds-pre"><code><div class="popover">
|
|
2764
|
+
<button class="btn btn--secondary popover__trigger"
|
|
2765
|
+
aria-haspopup="dialog" aria-expanded="false"
|
|
2766
|
+
aria-controls="pop">Detalles del plan</button>
|
|
2767
|
+
<div class="popover__panel" id="pop" role="dialog"
|
|
2768
|
+
aria-label="Detalles del plan" tabindex="-1">
|
|
2769
|
+
<p>Contenido con <a class="link" href="#">un enlace</a>.</p>
|
|
2770
|
+
</div>
|
|
2771
|
+
</div></code></pre>
|
|
2772
|
+
</div>
|
|
2773
|
+
</details>
|
|
2774
|
+
</div>
|
|
2775
|
+
|
|
2776
|
+
<!-- ButtonGroup -->
|
|
2777
|
+
<div class="ds-component" id="comp-button-group">
|
|
2778
|
+
<h3>ButtonGroup</h3>
|
|
2779
|
+
<p class="ds-spec">Botones adyacentes con bordes compartidos (radius solo en los extremos, bordes internos colapsados) · <span class="u-mono">role="group"</span> + <span class="u-mono">aria-label</span> · usa los <span class="u-mono">.btn</span> existentes. Para un único-seleccionado, usa SegmentedControl.</p>
|
|
2780
|
+
<div class="ds-demo">
|
|
2781
|
+
<div class="btn-group" role="group" aria-label="Navegación de semana">
|
|
2782
|
+
<button class="btn btn--secondary"><svg><use href="#i-chevron-left"/></svg>Anterior</button>
|
|
2783
|
+
<button class="btn btn--secondary">Hoy</button>
|
|
2784
|
+
<button class="btn btn--secondary">Siguiente<svg><use href="#i-chevron-right"/></svg></button>
|
|
2785
|
+
</div>
|
|
2786
|
+
</div>
|
|
2787
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2788
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2789
|
+
<pre class="ds-pre"><code><div class="btn-group" role="group" aria-label="Navegación de semana">
|
|
2790
|
+
<button class="btn btn--secondary">Anterior</button>
|
|
2791
|
+
<button class="btn btn--secondary">Hoy</button>
|
|
2792
|
+
<button class="btn btn--secondary">Siguiente</button>
|
|
2793
|
+
</div></code></pre>
|
|
2794
|
+
</div>
|
|
2795
|
+
</details>
|
|
2796
|
+
</div>
|
|
2797
|
+
|
|
2798
|
+
<!-- DatePicker -->
|
|
2799
|
+
<div class="ds-component" id="comp-datepicker">
|
|
2800
|
+
<h3>DatePicker</h3>
|
|
2801
|
+
<p class="ds-spec">Input + calendario en popover · rejilla <span class="u-mono">role="grid"</span>, encabezados <span class="u-mono">role="columnheader"</span> con <span class="u-mono">aria-label</span> completo, días <span class="u-mono">role="gridcell"</span> con <span class="u-mono">aria-label</span> de la fecha entera y <span class="u-mono">aria-selected</span> · las flechas mueven entre días · el input abre el calendario (click), Esc cierra y el foco entra al calendario · hoy marcado y un día seleccionado.</p>
|
|
2802
|
+
<div class="ds-demo" style="min-height:360px;align-items:flex-start">
|
|
2803
|
+
<div class="field" style="max-width:280px;width:100%">
|
|
2804
|
+
<label class="field__label" for="dpInput">Fecha de entrega</label>
|
|
2805
|
+
<div class="datepicker" id="demoDatepicker">
|
|
2806
|
+
<input class="datepicker__input" id="dpInput" type="text" readonly autocomplete="off"
|
|
2807
|
+
aria-haspopup="dialog" aria-expanded="false" aria-controls="dpCal" placeholder="Elige una fecha">
|
|
2808
|
+
<svg class="datepicker__icon" aria-hidden="true"><use href="#i-calendar"/></svg>
|
|
2809
|
+
<div class="datepicker__calendar" id="dpCal" role="dialog" aria-label="Elegir fecha" tabindex="-1">
|
|
2810
|
+
<div class="calendar">
|
|
2811
|
+
<div class="calendar__header">
|
|
2812
|
+
<button class="icon-btn icon-btn--ghost icon-btn--sm" type="button" data-cal-prev aria-label="Mes anterior"><svg><use href="#i-chevron-left"/></svg></button>
|
|
2813
|
+
<span class="calendar__title" aria-live="polite">—</span>
|
|
2814
|
+
<button class="icon-btn icon-btn--ghost icon-btn--sm" type="button" data-cal-next aria-label="Mes siguiente"><svg><use href="#i-chevron-right"/></svg></button>
|
|
2815
|
+
</div>
|
|
2816
|
+
<div class="calendar__weekdays" role="row">
|
|
2817
|
+
<span class="calendar__weekday" role="columnheader" aria-label="lunes">lu</span>
|
|
2818
|
+
<span class="calendar__weekday" role="columnheader" aria-label="martes">ma</span>
|
|
2819
|
+
<span class="calendar__weekday" role="columnheader" aria-label="miércoles">mi</span>
|
|
2820
|
+
<span class="calendar__weekday" role="columnheader" aria-label="jueves">ju</span>
|
|
2821
|
+
<span class="calendar__weekday" role="columnheader" aria-label="viernes">vi</span>
|
|
2822
|
+
<span class="calendar__weekday" role="columnheader" aria-label="sábado">sá</span>
|
|
2823
|
+
<span class="calendar__weekday" role="columnheader" aria-label="domingo">do</span>
|
|
2824
|
+
</div>
|
|
2825
|
+
<div class="calendar__grid" id="dpGrid" role="grid" aria-label="Calendario"></div>
|
|
2826
|
+
</div>
|
|
2827
|
+
</div>
|
|
2828
|
+
</div>
|
|
2829
|
+
</div>
|
|
2830
|
+
</div>
|
|
2831
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2832
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2833
|
+
<pre class="ds-pre"><code><div class="datepicker">
|
|
2834
|
+
<input class="datepicker__input" type="text" readonly
|
|
2835
|
+
aria-haspopup="dialog" aria-expanded="false" aria-controls="cal">
|
|
2836
|
+
<svg class="datepicker__icon" aria-hidden="true">…calendario…</svg>
|
|
2837
|
+
<div class="datepicker__calendar" id="cal" role="dialog"
|
|
2838
|
+
aria-label="Elegir fecha" tabindex="-1">
|
|
2839
|
+
<div class="calendar">
|
|
2840
|
+
<div class="calendar__header">
|
|
2841
|
+
<button aria-label="Mes anterior">…</button>
|
|
2842
|
+
<span class="calendar__title">julio 2026</span>
|
|
2843
|
+
<button aria-label="Mes siguiente">…</button>
|
|
2844
|
+
</div>
|
|
2845
|
+
<div class="calendar__weekdays" role="row">
|
|
2846
|
+
<span class="calendar__weekday" role="columnheader"
|
|
2847
|
+
aria-label="lunes">lu</span> …
|
|
2848
|
+
</div>
|
|
2849
|
+
<div class="calendar__grid" role="grid" aria-label="julio 2026">
|
|
2850
|
+
<button class="calendar__day calendar__day--today" role="gridcell"
|
|
2851
|
+
aria-label="viernes, 10 de julio de 2026"
|
|
2852
|
+
aria-selected="false">10</button>
|
|
2853
|
+
<button class="calendar__day calendar__day--selected" role="gridcell"
|
|
2854
|
+
aria-label="viernes, 17 de julio de 2026"
|
|
2855
|
+
aria-selected="true">17</button> …
|
|
2856
|
+
</div>
|
|
2857
|
+
</div>
|
|
2858
|
+
</div>
|
|
2859
|
+
</div></code></pre>
|
|
2860
|
+
</div>
|
|
2861
|
+
</details>
|
|
2862
|
+
</div>
|
|
2863
|
+
|
|
2864
|
+
<!-- FileUpload -->
|
|
2865
|
+
<div class="ds-component" id="comp-file-upload">
|
|
2866
|
+
<h3>FileUpload</h3>
|
|
2867
|
+
<p class="ds-spec">Dropzone + lista · el input <span class="u-mono">file</span> real va oculto pero con label asociado y <span class="u-mono">aria-describedby</span> de formatos y tamaño · la zona describe la acción · estado <span class="u-mono">.is-dragover</span> al arrastrar · el error no se comunica solo por color (icono + texto) · el item que sube reusa la barra <span class="u-mono">.progress</span>.</p>
|
|
2868
|
+
<div class="ds-demo ds-demo--col" style="max-width:480px">
|
|
2869
|
+
<div class="file-upload" id="demoFileUpload">
|
|
2870
|
+
<input class="file-upload__input" id="fuInput" type="file" multiple aria-describedby="fuHint">
|
|
2871
|
+
<label class="file-upload__label" for="fuInput">
|
|
2872
|
+
<svg aria-hidden="true"><use href="#i-upload"/></svg>
|
|
2873
|
+
<span class="file-upload__title">Arrastra archivos o elige</span>
|
|
2874
|
+
<span class="file-upload__button">Elegir archivos</span>
|
|
2875
|
+
<span class="file-upload__hint" id="fuHint">PDF, PNG o JPG · hasta 10 MB</span>
|
|
2876
|
+
</label>
|
|
2877
|
+
</div>
|
|
2878
|
+
<ul class="file-upload__list" id="fuList" aria-label="Archivos seleccionados">
|
|
2879
|
+
<li class="file-upload__item">
|
|
2880
|
+
<svg class="file-upload__icon" aria-hidden="true"><use href="#i-file"/></svg>
|
|
2881
|
+
<div class="file-upload__meta">
|
|
2882
|
+
<span class="file-upload__name">informe-anual-2026.pdf</span>
|
|
2883
|
+
<span class="file-upload__size">2.4 MB · Subiendo 45%</span>
|
|
2884
|
+
<div class="progress"><div class="progress__bar" style="width:45%" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" aria-label="Progreso de subida"></div></div>
|
|
2885
|
+
</div>
|
|
2886
|
+
<button class="file-upload__remove" type="button" aria-label="Cancelar informe-anual-2026.pdf"><svg><use href="#i-x"/></svg></button>
|
|
2887
|
+
</li>
|
|
2888
|
+
<li class="file-upload__item">
|
|
2889
|
+
<svg class="file-upload__icon" aria-hidden="true"><use href="#i-file"/></svg>
|
|
2890
|
+
<div class="file-upload__meta">
|
|
2891
|
+
<span class="file-upload__name">portada.png</span>
|
|
2892
|
+
<span class="file-upload__size"><svg aria-hidden="true"><use href="#i-circle-check"/></svg>820 KB · Completo</span>
|
|
2893
|
+
</div>
|
|
2894
|
+
<button class="file-upload__remove" type="button" aria-label="Quitar portada.png"><svg><use href="#i-x"/></svg></button>
|
|
2895
|
+
</li>
|
|
2896
|
+
<li class="file-upload__item file-upload__item--error">
|
|
2897
|
+
<svg class="file-upload__icon" aria-hidden="true"><use href="#i-circle-alert"/></svg>
|
|
2898
|
+
<div class="file-upload__meta">
|
|
2899
|
+
<span class="file-upload__name">video-demo.mov</span>
|
|
2900
|
+
<span class="file-upload__size"><svg aria-hidden="true"><use href="#i-circle-alert"/></svg>Formato no admitido · elige PDF, PNG o JPG</span>
|
|
2901
|
+
</div>
|
|
2902
|
+
<button class="file-upload__remove" type="button" aria-label="Quitar video-demo.mov"><svg><use href="#i-x"/></svg></button>
|
|
2903
|
+
</li>
|
|
2904
|
+
</ul>
|
|
2905
|
+
</div>
|
|
2906
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2907
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2908
|
+
<pre class="ds-pre"><code><div class="file-upload">
|
|
2909
|
+
<input class="file-upload__input" type="file" multiple
|
|
2910
|
+
aria-describedby="hint">
|
|
2911
|
+
<label class="file-upload__label" for="…">
|
|
2912
|
+
<svg aria-hidden="true">…subir…</svg>
|
|
2913
|
+
<span class="file-upload__title">Arrastra archivos o elige</span>
|
|
2914
|
+
<span class="file-upload__button">Elegir archivos</span>
|
|
2915
|
+
<span class="file-upload__hint" id="hint">PDF, PNG o JPG · hasta 10 MB</span>
|
|
2916
|
+
</label>
|
|
2917
|
+
</div>
|
|
2918
|
+
<ul class="file-upload__list">
|
|
2919
|
+
<li class="file-upload__item">
|
|
2920
|
+
<svg class="file-upload__icon">…</svg>
|
|
2921
|
+
<div class="file-upload__meta">
|
|
2922
|
+
<span class="file-upload__name">informe.pdf</span>
|
|
2923
|
+
<span class="file-upload__size">2.4 MB · Subiendo 45%</span>
|
|
2924
|
+
<div class="progress"><div class="progress__bar" style="width:45%"></div></div>
|
|
2925
|
+
</div>
|
|
2926
|
+
<button class="file-upload__remove" aria-label="Cancelar informe.pdf">×</button>
|
|
2927
|
+
</li>
|
|
2928
|
+
<li class="file-upload__item file-upload__item--error">
|
|
2929
|
+
<svg class="file-upload__icon">…alerta…</svg>
|
|
2930
|
+
<div class="file-upload__meta">
|
|
2931
|
+
<span class="file-upload__name">video.mov</span>
|
|
2932
|
+
<span class="file-upload__size">…alerta… Formato no admitido</span>
|
|
2933
|
+
</div>
|
|
2934
|
+
<button class="file-upload__remove" aria-label="Quitar video.mov">×</button>
|
|
2935
|
+
</li>
|
|
2936
|
+
</ul></code></pre>
|
|
2937
|
+
</div>
|
|
2938
|
+
</details>
|
|
2939
|
+
</div>
|
|
2940
|
+
|
|
2941
|
+
<!-- Stepper / Wizard -->
|
|
2942
|
+
<div class="ds-component" id="comp-stepper">
|
|
2943
|
+
<h3>Stepper / Wizard</h3>
|
|
2944
|
+
<p class="ds-spec"><span class="u-mono"><ol></span> · <span class="u-mono">aria-current="step"</span> en el paso actual · el completo muestra un check (no solo color), el próximo muestra su número · estados <span class="u-mono">--complete</span>/<span class="u-mono">--current</span>/<span class="u-mono">--upcoming</span> · <span class="u-mono">.step__connector</span> entre pasos · variante <span class="u-mono">--vertical</span>.</p>
|
|
2945
|
+
<div class="ds-demo ds-demo--col" style="gap:40px">
|
|
2946
|
+
<ol class="stepper" aria-label="Progreso de configuración">
|
|
2947
|
+
<li class="step step--complete">
|
|
2948
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2949
|
+
<span class="step__marker"><svg aria-hidden="true"><use href="#i-check"/></svg></span>
|
|
2950
|
+
<span class="step__label">Cuenta</span>
|
|
2951
|
+
</li>
|
|
2952
|
+
<li class="step step--complete">
|
|
2953
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2954
|
+
<span class="step__marker"><svg aria-hidden="true"><use href="#i-check"/></svg></span>
|
|
2955
|
+
<span class="step__label">Perfil</span>
|
|
2956
|
+
</li>
|
|
2957
|
+
<li class="step step--current" aria-current="step">
|
|
2958
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2959
|
+
<span class="step__marker">3</span>
|
|
2960
|
+
<span class="step__label">Facturación</span>
|
|
2961
|
+
</li>
|
|
2962
|
+
<li class="step step--upcoming">
|
|
2963
|
+
<span class="step__marker">4</span>
|
|
2964
|
+
<span class="step__label">Confirmar</span>
|
|
2965
|
+
</li>
|
|
2966
|
+
</ol>
|
|
2967
|
+
<ol class="stepper stepper--vertical" aria-label="Pasos de publicación" style="align-self:flex-start;min-width:220px">
|
|
2968
|
+
<li class="step step--complete">
|
|
2969
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2970
|
+
<span class="step__marker"><svg aria-hidden="true"><use href="#i-check"/></svg></span>
|
|
2971
|
+
<span class="step__label">Borrador guardado</span>
|
|
2972
|
+
</li>
|
|
2973
|
+
<li class="step step--current" aria-current="step">
|
|
2974
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2975
|
+
<span class="step__marker">2</span>
|
|
2976
|
+
<span class="step__label">Revisión del equipo</span>
|
|
2977
|
+
</li>
|
|
2978
|
+
<li class="step step--upcoming">
|
|
2979
|
+
<span class="step__marker">3</span>
|
|
2980
|
+
<span class="step__label">Publicación</span>
|
|
2981
|
+
</li>
|
|
2982
|
+
</ol>
|
|
2983
|
+
</div>
|
|
2984
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
2985
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2986
|
+
<pre class="ds-pre"><code><ol class="stepper" aria-label="Progreso de configuración">
|
|
2987
|
+
<li class="step step--complete">
|
|
2988
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2989
|
+
<span class="step__marker">…check…</span>
|
|
2990
|
+
<span class="step__label">Cuenta</span>
|
|
2991
|
+
</li>
|
|
2992
|
+
<li class="step step--current" aria-current="step">
|
|
2993
|
+
<span class="step__connector" aria-hidden="true"></span>
|
|
2994
|
+
<span class="step__marker">3</span>
|
|
2995
|
+
<span class="step__label">Facturación</span>
|
|
2996
|
+
</li>
|
|
2997
|
+
<li class="step step--upcoming">
|
|
2998
|
+
<span class="step__marker">4</span>
|
|
2999
|
+
<span class="step__label">Confirmar</span>
|
|
3000
|
+
</li>
|
|
3001
|
+
</ol>
|
|
3002
|
+
|
|
3003
|
+
<!-- Vertical: añade la clase --vertical al <ol> -->
|
|
3004
|
+
<ol class="stepper stepper--vertical">…</ol></code></pre>
|
|
3005
|
+
</div>
|
|
3006
|
+
</details>
|
|
3007
|
+
</div>
|
|
3008
|
+
|
|
3009
|
+
<!-- Kbd -->
|
|
3010
|
+
<div class="ds-component" id="comp-kbd">
|
|
3011
|
+
<h3>Kbd</h3>
|
|
3012
|
+
<p class="ds-spec">Tecla en <span class="u-mono"><kbd></span> con borde, sombra sutil de tinta y tipografía mono · tamaño pequeño, mínimo 20px · combos con "+" entre teclas.</p>
|
|
3013
|
+
<div class="ds-demo" style="gap:24px">
|
|
3014
|
+
<kbd class="kbd">Esc</kbd>
|
|
3015
|
+
<kbd class="kbd">Tab</kbd>
|
|
3016
|
+
<kbd class="kbd">⏎</kbd>
|
|
3017
|
+
<span class="kbd-combo"><kbd class="kbd">⌘</kbd> + <kbd class="kbd">K</kbd></span>
|
|
3018
|
+
<span class="kbd-combo"><kbd class="kbd">Ctrl</kbd> + <kbd class="kbd">S</kbd></span>
|
|
3019
|
+
<span class="kbd-combo"><kbd class="kbd">⌘</kbd> + <kbd class="kbd">⇧</kbd> + <kbd class="kbd">P</kbd></span>
|
|
3020
|
+
</div>
|
|
3021
|
+
<p class="ds-spec">Inline en el texto: abre la paleta con <kbd class="kbd">⌘</kbd> <kbd class="kbd">K</kbd> y guarda con <kbd class="kbd">Ctrl</kbd> <kbd class="kbd">S</kbd>.</p>
|
|
3022
|
+
<details class="ds-code"><summary>Ver código</summary>
|
|
3023
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
3024
|
+
<pre class="ds-pre"><code><kbd class="kbd">Esc</kbd>
|
|
3025
|
+
|
|
3026
|
+
<!-- Combo: "+" literal entre teclas -->
|
|
3027
|
+
<span class="kbd-combo">
|
|
3028
|
+
<kbd class="kbd">⌘</kbd> + <kbd class="kbd">K</kbd>
|
|
3029
|
+
</span></code></pre>
|
|
3030
|
+
</div>
|
|
3031
|
+
</details>
|
|
3032
|
+
</div>
|
|
2225
3033
|
</section>
|
|
2226
3034
|
|
|
2227
3035
|
<!-- ============================== MOTION ============================== -->
|
|
@@ -2264,11 +3072,11 @@ html, body { overflow-x: clip; }
|
|
|
2264
3072
|
<table class="table">
|
|
2265
3073
|
<thead><tr><th>Combinación</th><th class="num">Contraste</th><th>Veredicto</th></tr></thead>
|
|
2266
3074
|
<tbody>
|
|
2267
|
-
<tr><td><span class="u-mono">neutral-800</span> sobre blanco</td><td class="num"
|
|
2268
|
-
<tr><td>Blanco sobre <span class="u-mono">primary-500</span></td><td class="num"
|
|
2269
|
-
<tr><td><span class="u-mono">--link</span> (primary-700) sobre blanco</td><td class="num"
|
|
2270
|
-
<tr><td><span class="u-mono">primary-300</span> sobre blanco</td><td class="num"
|
|
2271
|
-
<tr><td>Tonos <span class="u-mono">--*-text</span> sobre <span class="u-mono">*-100</span></td><td class="num"
|
|
3075
|
+
<tr><td><span class="u-mono">neutral-800</span> sobre blanco</td><td class="num">12.42:1</td><td><span class="badge badge--success"><svg><use href="#i-circle-check"/></svg>AAA</span></td></tr>
|
|
3076
|
+
<tr><td>Blanco sobre <span class="u-mono">primary-500</span></td><td class="num">3.22:1</td><td><span class="badge badge--warning"><svg><use href="#i-triangle-alert"/></svg>Solo texto ≥18px o UI</span></td></tr>
|
|
3077
|
+
<tr><td><span class="u-mono">--link</span> (primary-700) sobre blanco</td><td class="num">5.94:1</td><td><span class="badge badge--success"><svg><use href="#i-circle-check"/></svg>AA texto normal</span></td></tr>
|
|
3078
|
+
<tr><td><span class="u-mono">primary-300</span> sobre blanco</td><td class="num">1.91:1</td><td><span class="badge badge--danger"><svg><use href="#i-circle-alert"/></svg>Nunca como texto</span></td></tr>
|
|
3079
|
+
<tr><td>Tonos <span class="u-mono">--*-text</span> sobre <span class="u-mono">*-100</span></td><td class="num">4.72–6.60:1</td><td><span class="badge badge--success"><svg><use href="#i-circle-check"/></svg>AA garantizado</span></td></tr>
|
|
2272
3080
|
</tbody>
|
|
2273
3081
|
</table>
|
|
2274
3082
|
</div>
|
|
@@ -2401,7 +3209,7 @@ html, body { overflow-x: clip; }
|
|
|
2401
3209
|
<svg><use href="#i-info"/></svg>
|
|
2402
3210
|
<div>
|
|
2403
3211
|
<p class="alert__title">Cómo consumirlo en un proyecto nuevo</p>
|
|
2404
|
-
<p class="alert__body">1)
|
|
3212
|
+
<p class="alert__body">1) Instala <span class="u-mono">@higinio/design-css</span> (e importa <span class="u-mono">@higinio/design-css/celeste/framework.css</span>) o copia <span class="u-mono">dist/celeste-clasica/celeste-clasica.css</span> (o solo <span class="u-mono">tokens.css</span>) e impórtalo antes de tus estilos, o pega el bloque <span class="u-mono">@theme</span> en tu CSS de Tailwind v4. 2) Aplica <span class="u-mono">.celeste-reset</span> al body. 3) Consume solo aliases semánticos. 4) Alterna <span class="u-mono">data-theme</span> en <span class="u-mono"><html></span> para light/dark.</p>
|
|
2405
3213
|
</div>
|
|
2406
3214
|
</div>
|
|
2407
3215
|
</section>
|
|
@@ -2410,9 +3218,22 @@ html, body { overflow-x: clip; }
|
|
|
2410
3218
|
<section id="instalacion">
|
|
2411
3219
|
<p class="ds-eyebrow">Sistema</p>
|
|
2412
3220
|
<h2>Instalación</h2>
|
|
2413
|
-
<p class="ds-lead">El sistema se distribuye como archivos en <span class="u-mono">dist/celeste-clasica/</span
|
|
3221
|
+
<p class="ds-lead">El sistema se distribuye como paquete npm (<span class="u-mono">@higinio/design-css</span>) y también como archivos sueltos en <span class="u-mono">dist/celeste-clasica/</span>. Instálalo o cópialos, y elige qué importar según tu stack (A/B/C). En todas: <strong>light por defecto</strong>; <span class="u-mono"><html data-theme="dark"></span> activa el modo oscuro, y los componentes consumen <strong>solo aliases semánticos</strong>, nunca hex.</p>
|
|
2414
3222
|
|
|
2415
|
-
<h3>
|
|
3223
|
+
<h3>Instalar desde npm (recomendado)</h3>
|
|
3224
|
+
<p>Un solo paquete con los dos sistemas en subrutas <span class="u-mono">/celeste/</span> y <span class="u-mono">/nocturna/</span>. Instálalo y usa las vías A/B/C apuntando a la subruta, en vez de a un archivo copiado.</p>
|
|
3225
|
+
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
3226
|
+
<pre class="ds-pre"><code>npm i @higinio/design-css
|
|
3227
|
+
|
|
3228
|
+
/* framework completo (vía A) */
|
|
3229
|
+
@import "@higinio/design-css/celeste/framework.css";
|
|
3230
|
+
/* o solo tokens (vía B) */
|
|
3231
|
+
@import "@higinio/design-css/celeste/tokens.css";
|
|
3232
|
+
/* o Tailwind v4 (vía C) */
|
|
3233
|
+
@import "@higinio/design-css/celeste/tailwind.css";</code></pre>
|
|
3234
|
+
</div>
|
|
3235
|
+
|
|
3236
|
+
<h3 style="margin-top:32px">A · CSS drop-in (framework completo)</h3>
|
|
2416
3237
|
<p>Para cualquier proyecto — HTML plano o cualquier framework. Trae variables + clases de componentes listas (tipo Bootstrap) y ya importa las fuentes. Aplica <span class="u-mono">.celeste-reset</span> al <span class="u-mono"><body></span>.</p>
|
|
2417
3238
|
<div class="ds-code-box"><button class="ds-copy">Copiar</button>
|
|
2418
3239
|
<pre class="ds-pre"><code><link rel="stylesheet" href="/estilos/celeste-clasica.css">
|
|
@@ -2523,14 +3344,14 @@ npm i tailwindcss @tailwindcss/postcss
|
|
|
2523
3344
|
</footer>
|
|
2524
3345
|
|
|
2525
3346
|
<!-- Modales de demostración -->
|
|
2526
|
-
<div class="modal" id="demoModal" role="dialog" aria-modal="true" aria-labelledby="demoModalTitle">
|
|
2527
|
-
<div class="modal__overlay"
|
|
2528
|
-
<div class="modal__panel">
|
|
3347
|
+
<div class="modal" id="demoModal" role="dialog" aria-modal="true" aria-labelledby="demoModalTitle" aria-describedby="demoModalDesc">
|
|
3348
|
+
<div class="modal__overlay"></div>
|
|
3349
|
+
<div class="modal__panel" tabindex="-1">
|
|
2529
3350
|
<div class="modal__header">
|
|
2530
3351
|
<h4 class="modal__title" id="demoModalTitle">¿Eliminar proyecto?</h4>
|
|
2531
3352
|
<button class="icon-btn icon-btn--ghost" data-modal-close aria-label="Cerrar"><svg><use href="#i-x"/></svg></button>
|
|
2532
3353
|
</div>
|
|
2533
|
-
<p style="font-size:var(--text-sm);color:var(--text-secondary)">Se eliminará
|
|
3354
|
+
<p id="demoModalDesc" style="font-size:var(--text-sm);color:var(--text-secondary)">Se eliminará «Panel Higinio» con sus 12 tableros. Esta acción no se puede deshacer.</p>
|
|
2534
3355
|
<div class="modal__footer">
|
|
2535
3356
|
<button class="btn btn--secondary" data-modal-close>Cancelar</button>
|
|
2536
3357
|
<button class="btn btn--danger" data-modal-close>Eliminar proyecto</button>
|
|
@@ -2540,7 +3361,7 @@ npm i tailwindcss @tailwindcss/postcss
|
|
|
2540
3361
|
|
|
2541
3362
|
<div class="modal" id="demoModalLg" role="dialog" aria-modal="true" aria-labelledby="demoModalLgTitle">
|
|
2542
3363
|
<div class="modal__overlay" data-modal-close></div>
|
|
2543
|
-
<div class="modal__panel modal__panel--lg">
|
|
3364
|
+
<div class="modal__panel modal__panel--lg" tabindex="-1">
|
|
2544
3365
|
<div class="modal__header">
|
|
2545
3366
|
<h4 class="modal__title" id="demoModalLgTitle">Invitar al equipo</h4>
|
|
2546
3367
|
<button class="icon-btn icon-btn--ghost" data-modal-close aria-label="Cerrar"><svg><use href="#i-x"/></svg></button>
|
|
@@ -2569,6 +3390,40 @@ npm i tailwindcss @tailwindcss/postcss
|
|
|
2569
3390
|
</div>
|
|
2570
3391
|
</div>
|
|
2571
3392
|
|
|
3393
|
+
<!-- Drawer de demostración (§10.29) -->
|
|
3394
|
+
<div class="drawer drawer--right" id="demoDrawer" role="dialog" aria-modal="true" aria-labelledby="demoDrawerTitle">
|
|
3395
|
+
<div class="drawer__overlay" data-drawer-close></div>
|
|
3396
|
+
<div class="drawer__panel" tabindex="-1">
|
|
3397
|
+
<div class="drawer__header">
|
|
3398
|
+
<h4 class="drawer__title" id="demoDrawerTitle">Filtrar proyectos</h4>
|
|
3399
|
+
<button class="icon-btn icon-btn--ghost" data-drawer-close aria-label="Cerrar"><svg><use href="#i-x"/></svg></button>
|
|
3400
|
+
</div>
|
|
3401
|
+
<div class="field">
|
|
3402
|
+
<label class="field__label" for="drawer-nombre">Nombre</label>
|
|
3403
|
+
<input class="input" id="drawer-nombre" type="text" autocomplete="off" placeholder="Buscar por nombre">
|
|
3404
|
+
</div>
|
|
3405
|
+
<div class="field">
|
|
3406
|
+
<label class="field__label" for="drawer-estado">Estado</label>
|
|
3407
|
+
<div class="select-wrap">
|
|
3408
|
+
<select class="select" id="drawer-estado">
|
|
3409
|
+
<option>Todos</option>
|
|
3410
|
+
<option>Activos</option>
|
|
3411
|
+
<option>Archivados</option>
|
|
3412
|
+
</select>
|
|
3413
|
+
</div>
|
|
3414
|
+
</div>
|
|
3415
|
+
<label class="switch">
|
|
3416
|
+
<input type="checkbox">
|
|
3417
|
+
<span class="switch__track"></span>
|
|
3418
|
+
Solo mis proyectos
|
|
3419
|
+
</label>
|
|
3420
|
+
<div class="drawer__footer">
|
|
3421
|
+
<button class="btn btn--secondary" data-drawer-close>Cancelar</button>
|
|
3422
|
+
<button class="btn btn--primary" data-drawer-close>Aplicar filtros</button>
|
|
3423
|
+
</div>
|
|
3424
|
+
</div>
|
|
3425
|
+
</div>
|
|
3426
|
+
|
|
2572
3427
|
<!-- Contenedor de toasts -->
|
|
2573
3428
|
<div class="toast-stack" id="toastStack" role="status" aria-live="polite"></div>
|
|
2574
3429
|
|
|
@@ -2863,30 +3718,102 @@ npm i tailwindcss @tailwindcss/postcss
|
|
|
2863
3718
|
});
|
|
2864
3719
|
});
|
|
2865
3720
|
|
|
2866
|
-
/* ---------- Modal ---------- */
|
|
2867
|
-
var
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
3721
|
+
/* ---------- Modal (§10.19): focus-trap + retorno de foco + Esc ---------- */
|
|
3722
|
+
var modalTrigger = null;
|
|
3723
|
+
var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
3724
|
+
function modalFocusables(modal) {
|
|
3725
|
+
return Array.prototype.filter.call(modal.querySelectorAll(FOCUSABLE), function (el) {
|
|
3726
|
+
return el.offsetWidth > 0 || el.offsetHeight > 0;
|
|
2872
3727
|
});
|
|
3728
|
+
}
|
|
3729
|
+
function openModal(modal, trigger) {
|
|
3730
|
+
if (!modal) return;
|
|
3731
|
+
modalTrigger = trigger || d.activeElement;
|
|
3732
|
+
modal.classList.add("is-open");
|
|
3733
|
+
var f = modalFocusables(modal);
|
|
3734
|
+
var panel = modal.querySelector(".modal__panel");
|
|
3735
|
+
window.setTimeout(function () { (f[0] || panel).focus(); }, 0);
|
|
3736
|
+
}
|
|
3737
|
+
function closeModal(modal) {
|
|
3738
|
+
if (!modal || !modal.classList.contains("is-open")) return;
|
|
3739
|
+
modal.classList.remove("is-open");
|
|
3740
|
+
if (modalTrigger && typeof modalTrigger.focus === "function") modalTrigger.focus();
|
|
3741
|
+
modalTrigger = null;
|
|
3742
|
+
}
|
|
3743
|
+
Array.prototype.forEach.call(d.querySelectorAll("[data-modal-open]"), function (btn) {
|
|
3744
|
+
btn.addEventListener("click", function () { openModal(d.getElementById(btn.getAttribute("data-modal-open")), btn); });
|
|
2873
3745
|
});
|
|
2874
3746
|
d.addEventListener("click", function (e) {
|
|
2875
|
-
if (e.target.closest("[data-modal-close]"))
|
|
2876
|
-
var modal = e.target.closest(".modal");
|
|
2877
|
-
if (modal) modal.classList.remove("is-open");
|
|
2878
|
-
}
|
|
3747
|
+
if (e.target.closest("[data-modal-close]")) closeModal(e.target.closest(".modal"));
|
|
2879
3748
|
});
|
|
2880
3749
|
d.addEventListener("keydown", function (e) {
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3750
|
+
var openM = d.querySelector(".modal.is-open");
|
|
3751
|
+
if (openM) {
|
|
3752
|
+
if (e.key === "Escape") { e.preventDefault(); closeModal(openM); return; }
|
|
3753
|
+
if (e.key === "Tab") {
|
|
3754
|
+
var f = modalFocusables(openM);
|
|
3755
|
+
if (!f.length) { e.preventDefault(); return; }
|
|
3756
|
+
var first = f[0], last = f[f.length - 1];
|
|
3757
|
+
if (!openM.contains(d.activeElement)) { e.preventDefault(); first.focus(); }
|
|
3758
|
+
else if (e.shiftKey && d.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
3759
|
+
else if (!e.shiftKey && d.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
3760
|
+
}
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
if (e.key === "Escape") {
|
|
3764
|
+
Array.prototype.forEach.call(d.querySelectorAll(".menu.is-open"), function (m) {
|
|
3765
|
+
m.classList.remove("is-open");
|
|
3766
|
+
});
|
|
3767
|
+
}
|
|
2888
3768
|
});
|
|
2889
3769
|
|
|
3770
|
+
/* ---------- Tabla (§10.21): orden + selección + indeterminate ---------- */
|
|
3771
|
+
var demoTable = d.getElementById("demoTable");
|
|
3772
|
+
if (demoTable) {
|
|
3773
|
+
var selectAll = d.getElementById("demoSelectAll");
|
|
3774
|
+
function rowBoxes() { return Array.prototype.slice.call(demoTable.querySelectorAll(".js-row-select")); }
|
|
3775
|
+
function syncSelectAll() {
|
|
3776
|
+
var boxes = rowBoxes();
|
|
3777
|
+
var checked = boxes.filter(function (b) { return b.checked; }).length;
|
|
3778
|
+
selectAll.checked = checked === boxes.length;
|
|
3779
|
+
selectAll.indeterminate = checked > 0 && checked < boxes.length;
|
|
3780
|
+
}
|
|
3781
|
+
rowBoxes().forEach(function (b) {
|
|
3782
|
+
b.addEventListener("change", function () {
|
|
3783
|
+
b.closest("tr").classList.toggle("row--selected", b.checked);
|
|
3784
|
+
syncSelectAll();
|
|
3785
|
+
});
|
|
3786
|
+
});
|
|
3787
|
+
if (selectAll) {
|
|
3788
|
+
selectAll.addEventListener("change", function () {
|
|
3789
|
+
rowBoxes().forEach(function (b) {
|
|
3790
|
+
b.checked = selectAll.checked;
|
|
3791
|
+
b.closest("tr").classList.toggle("row--selected", b.checked);
|
|
3792
|
+
});
|
|
3793
|
+
selectAll.indeterminate = false;
|
|
3794
|
+
});
|
|
3795
|
+
syncSelectAll();
|
|
3796
|
+
}
|
|
3797
|
+
var sortBtn = demoTable.querySelector(".th-sort[data-sort='monto']");
|
|
3798
|
+
if (sortBtn) {
|
|
3799
|
+
var sortTh = sortBtn.closest("th");
|
|
3800
|
+
sortBtn.addEventListener("click", function () {
|
|
3801
|
+
var dir = sortTh.getAttribute("aria-sort") === "ascending" ? "descending" : "ascending";
|
|
3802
|
+
sortTh.setAttribute("aria-sort", dir);
|
|
3803
|
+
var tbody = demoTable.querySelector("tbody");
|
|
3804
|
+
Array.prototype.slice.call(tbody.querySelectorAll("tr")).sort(function (a, b) {
|
|
3805
|
+
var va = +a.querySelector("[data-monto]").getAttribute("data-monto");
|
|
3806
|
+
var vb = +b.querySelector("[data-monto]").getAttribute("data-monto");
|
|
3807
|
+
return dir === "ascending" ? va - vb : vb - va;
|
|
3808
|
+
}).forEach(function (r) { tbody.appendChild(r); });
|
|
3809
|
+
});
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
/* ---------- Checkbox indeterminate (§10.9) — solo se fija por JS ---------- */
|
|
3814
|
+
var indet = d.getElementById("demoIndeterminate");
|
|
3815
|
+
if (indet) indet.indeterminate = true;
|
|
3816
|
+
|
|
2890
3817
|
/* ---------- Menu ---------- */
|
|
2891
3818
|
Array.prototype.forEach.call(d.querySelectorAll(".js-menu-toggle"), function (btn) {
|
|
2892
3819
|
btn.addEventListener("click", function (e) {
|
|
@@ -3054,6 +3981,316 @@ npm i tailwindcss @tailwindcss/postcss
|
|
|
3054
3981
|
} else {
|
|
3055
3982
|
Array.prototype.forEach.call(countEls, countUp);
|
|
3056
3983
|
}
|
|
3984
|
+
|
|
3985
|
+
/* ---------- Drawer (§10.29): focus-trap + retorno de foco + Esc ---------- */
|
|
3986
|
+
var drawerTrigger = null;
|
|
3987
|
+
function openDrawer(dr, trigger) {
|
|
3988
|
+
if (!dr) return;
|
|
3989
|
+
drawerTrigger = trigger || d.activeElement;
|
|
3990
|
+
dr.classList.add("is-open");
|
|
3991
|
+
var f = modalFocusables(dr);
|
|
3992
|
+
var panel = dr.querySelector(".drawer__panel");
|
|
3993
|
+
window.setTimeout(function () { (f[0] || panel).focus(); }, 0);
|
|
3994
|
+
}
|
|
3995
|
+
function closeDrawer(dr) {
|
|
3996
|
+
if (!dr || !dr.classList.contains("is-open")) return;
|
|
3997
|
+
dr.classList.remove("is-open");
|
|
3998
|
+
if (drawerTrigger && typeof drawerTrigger.focus === "function") drawerTrigger.focus();
|
|
3999
|
+
drawerTrigger = null;
|
|
4000
|
+
}
|
|
4001
|
+
Array.prototype.forEach.call(d.querySelectorAll("[data-drawer-open]"), function (btn) {
|
|
4002
|
+
btn.addEventListener("click", function () {
|
|
4003
|
+
openDrawer(d.getElementById(btn.getAttribute("data-drawer-open")), btn);
|
|
4004
|
+
});
|
|
4005
|
+
});
|
|
4006
|
+
d.addEventListener("click", function (e) {
|
|
4007
|
+
if (e.target.closest("[data-drawer-close]")) closeDrawer(e.target.closest(".drawer"));
|
|
4008
|
+
});
|
|
4009
|
+
d.addEventListener("keydown", function (e) {
|
|
4010
|
+
var openD = d.querySelector(".drawer.is-open");
|
|
4011
|
+
if (!openD) return;
|
|
4012
|
+
if (e.key === "Escape") { e.preventDefault(); closeDrawer(openD); return; }
|
|
4013
|
+
if (e.key === "Tab") {
|
|
4014
|
+
var f = modalFocusables(openD);
|
|
4015
|
+
if (!f.length) { e.preventDefault(); return; }
|
|
4016
|
+
var first = f[0], last = f[f.length - 1];
|
|
4017
|
+
if (!openD.contains(d.activeElement)) { e.preventDefault(); first.focus(); }
|
|
4018
|
+
else if (e.shiftKey && d.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
4019
|
+
else if (!e.shiftKey && d.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
4020
|
+
}
|
|
4021
|
+
});
|
|
4022
|
+
|
|
4023
|
+
/* ---------- Popover (§10.30): click, foco al panel, Esc y click-out ---------- */
|
|
4024
|
+
Array.prototype.forEach.call(d.querySelectorAll(".popover"), function (pop) {
|
|
4025
|
+
var trigger = pop.querySelector(".popover__trigger");
|
|
4026
|
+
var panel = pop.querySelector(".popover__panel");
|
|
4027
|
+
if (!trigger || !panel) return;
|
|
4028
|
+
function openPop() {
|
|
4029
|
+
pop.classList.add("is-open");
|
|
4030
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
4031
|
+
window.setTimeout(function () { panel.focus(); }, 0);
|
|
4032
|
+
}
|
|
4033
|
+
function closePop(returnFocus) {
|
|
4034
|
+
if (!pop.classList.contains("is-open")) return;
|
|
4035
|
+
pop.classList.remove("is-open");
|
|
4036
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
4037
|
+
if (returnFocus) trigger.focus();
|
|
4038
|
+
}
|
|
4039
|
+
trigger.addEventListener("click", function (e) {
|
|
4040
|
+
e.stopPropagation();
|
|
4041
|
+
if (pop.classList.contains("is-open")) closePop(true); else openPop();
|
|
4042
|
+
});
|
|
4043
|
+
d.addEventListener("click", function (e) {
|
|
4044
|
+
if (pop.classList.contains("is-open") && !pop.contains(e.target)) closePop(false);
|
|
4045
|
+
});
|
|
4046
|
+
pop.addEventListener("keydown", function (e) {
|
|
4047
|
+
if (e.key === "Escape") { e.preventDefault(); closePop(true); }
|
|
4048
|
+
});
|
|
4049
|
+
});
|
|
4050
|
+
|
|
4051
|
+
/* ---------- Combobox (§10.28): filtro en vivo + navegación por teclado ---------- */
|
|
4052
|
+
var cbx = d.getElementById("cbx");
|
|
4053
|
+
if (cbx) {
|
|
4054
|
+
var cbxInput = d.getElementById("cbxInput");
|
|
4055
|
+
var cbxList = d.getElementById("cbxList");
|
|
4056
|
+
var CITIES = ["Aguascalientes", "Ciudad de México", "Guadalajara", "Mérida",
|
|
4057
|
+
"Monterrey", "Puebla", "Querétaro", "Tijuana"];
|
|
4058
|
+
var cbxActive = -1;
|
|
4059
|
+
function cbxOptions() {
|
|
4060
|
+
return Array.prototype.slice.call(cbxList.querySelectorAll(".combobox__option"));
|
|
4061
|
+
}
|
|
4062
|
+
function cbxRender() {
|
|
4063
|
+
var q = cbxInput.value.trim().toLowerCase();
|
|
4064
|
+
var matches = CITIES.filter(function (c) { return c.toLowerCase().indexOf(q) !== -1; });
|
|
4065
|
+
cbxList.innerHTML = "";
|
|
4066
|
+
if (!matches.length) {
|
|
4067
|
+
var empty = d.createElement("li");
|
|
4068
|
+
empty.className = "combobox__empty";
|
|
4069
|
+
empty.textContent = "Sin resultados";
|
|
4070
|
+
cbxList.appendChild(empty);
|
|
4071
|
+
} else {
|
|
4072
|
+
matches.forEach(function (c, i) {
|
|
4073
|
+
var li = d.createElement("li");
|
|
4074
|
+
li.className = "combobox__option";
|
|
4075
|
+
li.id = "cbx-opt-" + i;
|
|
4076
|
+
li.setAttribute("role", "option");
|
|
4077
|
+
li.setAttribute("aria-selected", c === cbxInput.value ? "true" : "false");
|
|
4078
|
+
li.appendChild(d.createTextNode(c));
|
|
4079
|
+
li.insertAdjacentHTML("beforeend",
|
|
4080
|
+
'<svg class="combobox__check" aria-hidden="true"><use href="#i-check"/></svg>');
|
|
4081
|
+
cbxList.appendChild(li);
|
|
4082
|
+
});
|
|
4083
|
+
}
|
|
4084
|
+
cbxActive = -1;
|
|
4085
|
+
cbxInput.removeAttribute("aria-activedescendant");
|
|
4086
|
+
}
|
|
4087
|
+
function cbxOpen() { cbx.classList.add("is-open"); cbxInput.setAttribute("aria-expanded", "true"); }
|
|
4088
|
+
function cbxClose() { cbx.classList.remove("is-open"); cbxInput.setAttribute("aria-expanded", "false"); cbxSetActive(-1); }
|
|
4089
|
+
function cbxSetActive(i) {
|
|
4090
|
+
var opts = cbxOptions();
|
|
4091
|
+
opts.forEach(function (o) { o.classList.remove("is-active"); });
|
|
4092
|
+
cbxActive = i;
|
|
4093
|
+
if (i >= 0 && opts[i]) {
|
|
4094
|
+
opts[i].classList.add("is-active");
|
|
4095
|
+
cbxInput.setAttribute("aria-activedescendant", opts[i].id);
|
|
4096
|
+
opts[i].scrollIntoView({ block: "nearest" });
|
|
4097
|
+
} else {
|
|
4098
|
+
cbxInput.removeAttribute("aria-activedescendant");
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
function cbxChoose(opt) {
|
|
4102
|
+
if (!opt || opt.classList.contains("combobox__empty")) return;
|
|
4103
|
+
cbxInput.value = opt.textContent.trim();
|
|
4104
|
+
cbxRender();
|
|
4105
|
+
cbxClose();
|
|
4106
|
+
}
|
|
4107
|
+
cbxInput.addEventListener("input", function () { cbxRender(); cbxOpen(); });
|
|
4108
|
+
cbxInput.addEventListener("focus", function () { cbxRender(); cbxOpen(); });
|
|
4109
|
+
cbxInput.addEventListener("keydown", function (e) {
|
|
4110
|
+
var opts = cbxOptions();
|
|
4111
|
+
if (e.key === "ArrowDown") {
|
|
4112
|
+
e.preventDefault();
|
|
4113
|
+
if (!cbx.classList.contains("is-open")) cbxOpen();
|
|
4114
|
+
if (opts.length) cbxSetActive(Math.min(opts.length - 1, cbxActive + 1));
|
|
4115
|
+
} else if (e.key === "ArrowUp") {
|
|
4116
|
+
e.preventDefault();
|
|
4117
|
+
if (opts.length) cbxSetActive(Math.max(0, cbxActive - 1));
|
|
4118
|
+
} else if (e.key === "Home") {
|
|
4119
|
+
if (opts.length) { e.preventDefault(); cbxSetActive(0); }
|
|
4120
|
+
} else if (e.key === "End") {
|
|
4121
|
+
if (opts.length) { e.preventDefault(); cbxSetActive(opts.length - 1); }
|
|
4122
|
+
} else if (e.key === "Enter") {
|
|
4123
|
+
if (cbxActive >= 0 && opts[cbxActive]) { e.preventDefault(); cbxChoose(opts[cbxActive]); }
|
|
4124
|
+
} else if (e.key === "Escape") {
|
|
4125
|
+
if (cbx.classList.contains("is-open")) { e.preventDefault(); cbxClose(); }
|
|
4126
|
+
}
|
|
4127
|
+
});
|
|
4128
|
+
cbxList.addEventListener("mousedown", function (e) {
|
|
4129
|
+
var opt = e.target.closest(".combobox__option");
|
|
4130
|
+
if (opt) { e.preventDefault(); cbxChoose(opt); }
|
|
4131
|
+
});
|
|
4132
|
+
cbxInput.addEventListener("blur", function () { window.setTimeout(cbxClose, 120); });
|
|
4133
|
+
d.addEventListener("click", function (e) { if (!cbx.contains(e.target)) cbxClose(); });
|
|
4134
|
+
cbxRender();
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
/* ---------- Búsqueda (§10.28): limpiar ---------- */
|
|
4138
|
+
Array.prototype.forEach.call(d.querySelectorAll(".search"), function (s) {
|
|
4139
|
+
var input = s.querySelector(".search__input");
|
|
4140
|
+
var clear = s.querySelector(".search__clear");
|
|
4141
|
+
if (!input || !clear) return;
|
|
4142
|
+
clear.addEventListener("click", function () {
|
|
4143
|
+
input.value = "";
|
|
4144
|
+
input.focus();
|
|
4145
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
4146
|
+
});
|
|
4147
|
+
});
|
|
4148
|
+
|
|
4149
|
+
/* ---------- DatePicker (§10.32): calendario + navegación por teclado ---------- */
|
|
4150
|
+
var dp = d.getElementById("demoDatepicker");
|
|
4151
|
+
if (dp) {
|
|
4152
|
+
var dpInput = d.getElementById("dpInput");
|
|
4153
|
+
var dpCal = d.getElementById("dpCal");
|
|
4154
|
+
var dpGrid = d.getElementById("dpGrid");
|
|
4155
|
+
var dpTitle = dp.querySelector(".calendar__title");
|
|
4156
|
+
var MONTHS = ["enero", "febrero", "marzo", "abril", "mayo", "junio",
|
|
4157
|
+
"julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"];
|
|
4158
|
+
var fmtLong = new Intl.DateTimeFormat("es-MX", { weekday: "long", day: "numeric", month: "long", year: "numeric" });
|
|
4159
|
+
var fmtInput = new Intl.DateTimeFormat("es-MX", { day: "2-digit", month: "2-digit", year: "numeric" });
|
|
4160
|
+
function atMidnight(dt) { return new Date(dt.getFullYear(), dt.getMonth(), dt.getDate()); }
|
|
4161
|
+
function sameDay(a, b) {
|
|
4162
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
4163
|
+
}
|
|
4164
|
+
var today = atMidnight(new Date());
|
|
4165
|
+
var selected = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 7);
|
|
4166
|
+
var focusDate = new Date(selected);
|
|
4167
|
+
var view = new Date(selected.getFullYear(), selected.getMonth(), 1);
|
|
4168
|
+
function dpRender() {
|
|
4169
|
+
var y = view.getFullYear(), m = view.getMonth();
|
|
4170
|
+
dpTitle.textContent = MONTHS[m] + " " + y;
|
|
4171
|
+
dpGrid.setAttribute("aria-label", MONTHS[m] + " " + y);
|
|
4172
|
+
dpGrid.innerHTML = "";
|
|
4173
|
+
var startDow = (new Date(y, m, 1).getDay() + 6) % 7; // lunes = 0
|
|
4174
|
+
var daysInMonth = new Date(y, m + 1, 0).getDate();
|
|
4175
|
+
var weeks = Math.ceil((startDow + daysInMonth) / 7);
|
|
4176
|
+
var start = new Date(y, m, 1 - startDow);
|
|
4177
|
+
for (var i = 0; i < weeks * 7; i++) {
|
|
4178
|
+
var cell = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
|
|
4179
|
+
var btn = d.createElement("button");
|
|
4180
|
+
btn.type = "button";
|
|
4181
|
+
btn.className = "calendar__day";
|
|
4182
|
+
btn.setAttribute("role", "gridcell");
|
|
4183
|
+
btn.textContent = String(cell.getDate());
|
|
4184
|
+
if (cell.getMonth() !== m) btn.classList.add("calendar__day--outside");
|
|
4185
|
+
if (sameDay(cell, today)) btn.classList.add("calendar__day--today");
|
|
4186
|
+
var isSel = sameDay(cell, selected);
|
|
4187
|
+
if (isSel) btn.classList.add("calendar__day--selected");
|
|
4188
|
+
btn.setAttribute("aria-selected", isSel ? "true" : "false");
|
|
4189
|
+
btn.setAttribute("aria-label", fmtLong.format(cell));
|
|
4190
|
+
btn.tabIndex = sameDay(cell, focusDate) ? 0 : -1;
|
|
4191
|
+
btn.setAttribute("data-ts", String(cell.getTime()));
|
|
4192
|
+
dpGrid.appendChild(btn);
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
function dpButtonFor(dt) { return dpGrid.querySelector('[data-ts="' + atMidnight(dt).getTime() + '"]'); }
|
|
4196
|
+
function dpMoveFocus(dt) {
|
|
4197
|
+
focusDate = atMidnight(dt);
|
|
4198
|
+
if (focusDate.getMonth() !== view.getMonth() || focusDate.getFullYear() !== view.getFullYear()) {
|
|
4199
|
+
view = new Date(focusDate.getFullYear(), focusDate.getMonth(), 1);
|
|
4200
|
+
dpRender();
|
|
4201
|
+
} else {
|
|
4202
|
+
Array.prototype.forEach.call(dpGrid.querySelectorAll(".calendar__day"), function (b) {
|
|
4203
|
+
b.tabIndex = b.getAttribute("data-ts") === String(focusDate.getTime()) ? 0 : -1;
|
|
4204
|
+
});
|
|
4205
|
+
}
|
|
4206
|
+
var b = dpButtonFor(focusDate);
|
|
4207
|
+
if (b) b.focus();
|
|
4208
|
+
}
|
|
4209
|
+
function dpOpen() {
|
|
4210
|
+
dp.classList.add("is-open");
|
|
4211
|
+
dpInput.setAttribute("aria-expanded", "true");
|
|
4212
|
+
focusDate = new Date(selected);
|
|
4213
|
+
view = new Date(focusDate.getFullYear(), focusDate.getMonth(), 1);
|
|
4214
|
+
dpRender();
|
|
4215
|
+
window.setTimeout(function () { var b = dpButtonFor(focusDate); if (b) b.focus(); else dpCal.focus(); }, 0);
|
|
4216
|
+
}
|
|
4217
|
+
function dpClose(returnFocus) {
|
|
4218
|
+
if (!dp.classList.contains("is-open")) return;
|
|
4219
|
+
dp.classList.remove("is-open");
|
|
4220
|
+
dpInput.setAttribute("aria-expanded", "false");
|
|
4221
|
+
if (returnFocus) dpInput.focus();
|
|
4222
|
+
}
|
|
4223
|
+
function dpSelect(dt) {
|
|
4224
|
+
selected = atMidnight(dt);
|
|
4225
|
+
dpInput.value = fmtInput.format(selected);
|
|
4226
|
+
dpClose(true);
|
|
4227
|
+
}
|
|
4228
|
+
dpInput.addEventListener("click", function () {
|
|
4229
|
+
if (dp.classList.contains("is-open")) dpClose(true); else dpOpen();
|
|
4230
|
+
});
|
|
4231
|
+
dpInput.addEventListener("keydown", function (e) {
|
|
4232
|
+
if ((e.key === "Enter" || e.key === " " || e.key === "ArrowDown") && !dp.classList.contains("is-open")) {
|
|
4233
|
+
e.preventDefault(); dpOpen();
|
|
4234
|
+
}
|
|
4235
|
+
});
|
|
4236
|
+
dp.querySelector("[data-cal-prev]").addEventListener("click", function () {
|
|
4237
|
+
view = new Date(view.getFullYear(), view.getMonth() - 1, 1); dpRender();
|
|
4238
|
+
});
|
|
4239
|
+
dp.querySelector("[data-cal-next]").addEventListener("click", function () {
|
|
4240
|
+
view = new Date(view.getFullYear(), view.getMonth() + 1, 1); dpRender();
|
|
4241
|
+
});
|
|
4242
|
+
dpGrid.addEventListener("click", function (e) {
|
|
4243
|
+
var btn = e.target.closest(".calendar__day");
|
|
4244
|
+
if (btn) dpSelect(new Date(Number(btn.getAttribute("data-ts"))));
|
|
4245
|
+
});
|
|
4246
|
+
dpGrid.addEventListener("keydown", function (e) {
|
|
4247
|
+
var delta = null;
|
|
4248
|
+
if (e.key === "ArrowLeft") delta = -1;
|
|
4249
|
+
else if (e.key === "ArrowRight") delta = 1;
|
|
4250
|
+
else if (e.key === "ArrowUp") delta = -7;
|
|
4251
|
+
else if (e.key === "ArrowDown") delta = 7;
|
|
4252
|
+
else if (e.key === "Home") delta = -((focusDate.getDay() + 6) % 7);
|
|
4253
|
+
else if (e.key === "End") delta = 6 - ((focusDate.getDay() + 6) % 7);
|
|
4254
|
+
else if (e.key === "PageUp") { e.preventDefault(); dpMoveFocus(new Date(focusDate.getFullYear(), focusDate.getMonth() - 1, focusDate.getDate())); return; }
|
|
4255
|
+
else if (e.key === "PageDown") { e.preventDefault(); dpMoveFocus(new Date(focusDate.getFullYear(), focusDate.getMonth() + 1, focusDate.getDate())); return; }
|
|
4256
|
+
else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); dpSelect(focusDate); return; }
|
|
4257
|
+
else return;
|
|
4258
|
+
e.preventDefault();
|
|
4259
|
+
dpMoveFocus(new Date(focusDate.getFullYear(), focusDate.getMonth(), focusDate.getDate() + delta));
|
|
4260
|
+
});
|
|
4261
|
+
dpCal.addEventListener("keydown", function (e) {
|
|
4262
|
+
if (e.key === "Escape") { e.preventDefault(); dpClose(true); }
|
|
4263
|
+
});
|
|
4264
|
+
d.addEventListener("click", function (e) {
|
|
4265
|
+
if (dp.classList.contains("is-open") && !dp.contains(e.target)) dpClose(false);
|
|
4266
|
+
});
|
|
4267
|
+
dpInput.value = fmtInput.format(selected);
|
|
4268
|
+
dpRender();
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
/* ---------- FileUpload (§10.33): dragover + quitar item ---------- */
|
|
4272
|
+
var fu = d.getElementById("demoFileUpload");
|
|
4273
|
+
if (fu) {
|
|
4274
|
+
["dragenter", "dragover"].forEach(function (ev) {
|
|
4275
|
+
fu.addEventListener(ev, function (e) { e.preventDefault(); fu.classList.add("is-dragover"); });
|
|
4276
|
+
});
|
|
4277
|
+
["dragleave", "drop"].forEach(function (ev) {
|
|
4278
|
+
fu.addEventListener(ev, function (e) {
|
|
4279
|
+
e.preventDefault();
|
|
4280
|
+
if (ev === "dragleave" && e.relatedTarget && fu.contains(e.relatedTarget)) return;
|
|
4281
|
+
fu.classList.remove("is-dragover");
|
|
4282
|
+
});
|
|
4283
|
+
});
|
|
4284
|
+
}
|
|
4285
|
+
var fuList = d.getElementById("fuList");
|
|
4286
|
+
if (fuList) {
|
|
4287
|
+
fuList.addEventListener("click", function (e) {
|
|
4288
|
+
var btn = e.target.closest(".file-upload__remove");
|
|
4289
|
+
if (!btn) return;
|
|
4290
|
+
var item = btn.closest(".file-upload__item");
|
|
4291
|
+
if (item && item.parentNode) item.parentNode.removeChild(item);
|
|
4292
|
+
});
|
|
4293
|
+
}
|
|
3057
4294
|
})();
|
|
3058
4295
|
</script>
|
|
3059
4296
|
</body>
|