neba 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/dist/components/alert/Alert.d.ts +7 -1
- package/dist/components/alert/Alert.js +1 -1
- package/dist/components/animate-appear/AnimateAppear.d.ts +55 -0
- package/dist/components/animate-appear/AnimateAppear.js +1 -0
- package/dist/components/animate-appear/index.d.ts +2 -0
- package/dist/components/animate-appear/index.js +1 -0
- package/dist/components/animate-blink/AnimateBlink.d.ts +31 -0
- package/dist/components/animate-blink/AnimateBlink.js +1 -0
- package/dist/components/animate-blink/index.d.ts +2 -0
- package/dist/components/animate-blink/index.js +1 -0
- package/dist/components/animate-fade/AnimateFade.d.ts +31 -0
- package/dist/components/animate-fade/AnimateFade.js +1 -0
- package/dist/components/animate-fade/index.d.ts +2 -0
- package/dist/components/animate-fade/index.js +1 -0
- package/dist/components/animate-grow/AnimateGrow.d.ts +41 -0
- package/dist/components/animate-grow/AnimateGrow.js +1 -0
- package/dist/components/animate-grow/index.d.ts +2 -0
- package/dist/components/animate-grow/index.js +1 -0
- package/dist/components/animate-headline/AnimateHeadline.d.ts +55 -0
- package/dist/components/animate-headline/AnimateHeadline.js +1 -0
- package/dist/components/animate-headline/index.d.ts +2 -0
- package/dist/components/animate-headline/index.js +1 -0
- package/dist/components/animate-lighting/AnimateLighting.d.ts +62 -0
- package/dist/components/animate-lighting/AnimateLighting.js +1 -0
- package/dist/components/animate-lighting/index.d.ts +2 -0
- package/dist/components/animate-lighting/index.js +1 -0
- package/dist/components/animate-marquee/AnimateMarquee.d.ts +65 -0
- package/dist/components/animate-marquee/AnimateMarquee.js +1 -0
- package/dist/components/animate-marquee/index.d.ts +2 -0
- package/dist/components/animate-marquee/index.js +1 -0
- package/dist/components/animate-rotate/AnimateRotate.d.ts +48 -0
- package/dist/components/animate-rotate/AnimateRotate.js +1 -0
- package/dist/components/animate-rotate/index.d.ts +2 -0
- package/dist/components/animate-rotate/index.js +1 -0
- package/dist/components/animate-slide/AnimateSlide.d.ts +46 -0
- package/dist/components/animate-slide/AnimateSlide.js +1 -0
- package/dist/components/animate-slide/index.d.ts +2 -0
- package/dist/components/animate-slide/index.js +1 -0
- package/dist/components/animate-typing/AnimateTyping.d.ts +58 -0
- package/dist/components/animate-typing/AnimateTyping.js +1 -0
- package/dist/components/animate-typing/index.d.ts +2 -0
- package/dist/components/animate-typing/index.js +1 -0
- package/dist/components/animate-zoom/AnimateZoom.d.ts +37 -0
- package/dist/components/animate-zoom/AnimateZoom.js +1 -0
- package/dist/components/animate-zoom/index.d.ts +2 -0
- package/dist/components/animate-zoom/index.js +1 -0
- package/dist/components/aspect-ratio/AspectRatio.d.ts +63 -0
- package/dist/components/aspect-ratio/AspectRatio.js +1 -0
- package/dist/components/aspect-ratio/index.d.ts +2 -0
- package/dist/components/aspect-ratio/index.js +1 -0
- package/dist/components/avatar/Avatar.d.ts +7 -1
- package/dist/components/avatar/Avatar.js +1 -1
- package/dist/components/blockquote/Blockquote.d.ts +7 -1
- package/dist/components/blockquote/Blockquote.js +1 -1
- package/dist/components/box/Box.d.ts +7 -1
- package/dist/components/box/Box.js +1 -1
- package/dist/components/chip/Chip.d.ts +7 -1
- package/dist/components/chip/Chip.js +1 -1
- package/dist/components/color-picker/ColorPicker.d.ts +102 -0
- package/dist/components/color-picker/ColorPicker.js +1 -0
- package/dist/components/color-picker/index.d.ts +2 -0
- package/dist/components/color-picker/index.js +1 -0
- package/dist/components/drawer/Drawer.d.ts +145 -0
- package/dist/components/drawer/Drawer.js +1 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +1 -0
- package/dist/components/icon/Icon.d.ts +8 -1
- package/dist/components/icon/Icon.js +1 -1
- package/dist/components/popover/Popover.d.ts +109 -0
- package/dist/components/popover/Popover.js +1 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +1 -0
- package/dist/components/skeleton/Skeleton.d.ts +76 -0
- package/dist/components/skeleton/Skeleton.js +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/typography/Typography.d.ts +7 -1
- package/dist/components/typography/Typography.js +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1 -1
- package/dist/internal/animate.d.ts +175 -0
- package/dist/internal/animate.js +1 -0
- package/dist/internal/color.d.ts +108 -0
- package/dist/internal/color.js +1 -0
- package/dist/internal/i18n.d.ts +25 -0
- package/dist/internal/i18n.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +379 -0
- package/dist/types.d.ts +112 -0
- package/package.json +8 -8
package/dist/tailwind.css
CHANGED
|
@@ -962,6 +962,48 @@
|
|
|
962
962
|
animation-delay: calc(var(--n-i, 0) * 160ms);
|
|
963
963
|
}
|
|
964
964
|
|
|
965
|
+
/*
|
|
966
|
+
* The highlight travelling across a placeholder.
|
|
967
|
+
*
|
|
968
|
+
* `inset-inline-start` rather than a transform, the same trade `neba-sweep`
|
|
969
|
+
* makes and for the same reason: it runs the other way under RTL without being
|
|
970
|
+
* told, and the layout pass it costs is confined to a box with nothing in it.
|
|
971
|
+
*
|
|
972
|
+
* A pseudo-element rather than a child, so a Skeleton is one element per shape
|
|
973
|
+
* and a stack of ten lines is ten nodes rather than twenty. The gradient is
|
|
974
|
+
* symmetric, so it needs no direction of its own.
|
|
975
|
+
*/
|
|
976
|
+
@keyframes neba-skeleton-sweep {
|
|
977
|
+
from {
|
|
978
|
+
inset-inline-start: -60%;
|
|
979
|
+
}
|
|
980
|
+
to {
|
|
981
|
+
inset-inline-start: 100%;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.neba-skeleton::after {
|
|
986
|
+
content: '';
|
|
987
|
+
position: absolute;
|
|
988
|
+
inset-block: 0;
|
|
989
|
+
inline-size: 60%;
|
|
990
|
+
background-image: linear-gradient(90deg, transparent, var(--n-panel-press), transparent);
|
|
991
|
+
animation: neba-skeleton-sweep 1.5s var(--neba-ease) infinite;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/* The reduced-motion stand-in: the highlight stops travelling and the whole
|
|
995
|
+
placeholder breathes instead. Colour, which is the axis every other state in
|
|
996
|
+
the library already uses. */
|
|
997
|
+
@keyframes neba-skeleton-pulse {
|
|
998
|
+
0%,
|
|
999
|
+
100% {
|
|
1000
|
+
background-color: transparent;
|
|
1001
|
+
}
|
|
1002
|
+
50% {
|
|
1003
|
+
background-color: var(--n-panel-press);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
965
1007
|
/* The reduced-motion stand-in for the sweep: the segment stops travelling and
|
|
966
1008
|
the whole groove pulses instead. Colour, which is the axis every other state
|
|
967
1009
|
in the library already uses. */
|
|
@@ -975,6 +1017,308 @@
|
|
|
975
1017
|
}
|
|
976
1018
|
}
|
|
977
1019
|
|
|
1020
|
+
/* ---------------------------------------------------------------------------
|
|
1021
|
+
* Animation
|
|
1022
|
+
*
|
|
1023
|
+
* The `Animate*` components, and the `transition` prop that shares their
|
|
1024
|
+
* effects. Everything below is real CSS for the reason the loading indicators
|
|
1025
|
+
* above are: a keyframe is not a Tailwind variant, so there is nothing to
|
|
1026
|
+
* express one with.
|
|
1027
|
+
*
|
|
1028
|
+
* The whole set is built on one idea. An effect is a single `@keyframes` that
|
|
1029
|
+
* runs from a state written entirely in `--n-anim-*` custom properties to the
|
|
1030
|
+
* element's natural one — so `src/internal/animate.ts` never generates CSS, it
|
|
1031
|
+
* only fills slots, and running an effect backwards is `animation-direction:
|
|
1032
|
+
* reverse` rather than a second keyframe. That is what makes `mode="out"` cost
|
|
1033
|
+
* nothing on all six.
|
|
1034
|
+
*
|
|
1035
|
+
* `fill-mode` is `both` throughout, which is what lets an animation that has
|
|
1036
|
+
* not been triggered yet simply sit paused on its own first frame. Without it,
|
|
1037
|
+
* an element waiting to be scrolled into view would be fully drawn and then
|
|
1038
|
+
* blink out the moment it arrived.
|
|
1039
|
+
*
|
|
1040
|
+
* This is also where the library's rule against transforms is at its narrowest.
|
|
1041
|
+
* A *control* never moves — that rule is about a button resampling its label
|
|
1042
|
+
* under the pointer, and it still holds without exception. An `Animate*` wraps
|
|
1043
|
+
* content the caller asked to have moved, and it moves it with the independent
|
|
1044
|
+
* `translate`, `scale` and `rotate` properties rather than the `transform`
|
|
1045
|
+
* shorthand, so a caller's own transform on the same element survives.
|
|
1046
|
+
* ------------------------------------------------------------------------- */
|
|
1047
|
+
|
|
1048
|
+
.neba-anim {
|
|
1049
|
+
animation-duration: var(--n-anim-duration, 320ms);
|
|
1050
|
+
animation-delay: var(--n-anim-delay, 0ms);
|
|
1051
|
+
animation-timing-function: var(--n-anim-ease, var(--neba-ease));
|
|
1052
|
+
animation-iteration-count: var(--n-anim-repeat, 1);
|
|
1053
|
+
animation-direction: var(--n-anim-direction, normal);
|
|
1054
|
+
animation-fill-mode: both;
|
|
1055
|
+
animation-play-state: var(--n-anim-state, running);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
@keyframes neba-anim-fade {
|
|
1059
|
+
from {
|
|
1060
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1061
|
+
}
|
|
1062
|
+
to {
|
|
1063
|
+
opacity: 1;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
.neba-anim-fade {
|
|
1068
|
+
animation-name: neba-anim-fade;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
/* Grow and Zoom share this one: they are the same arithmetic at two strengths,
|
|
1072
|
+
separated by their defaults and by their origin rather than by their maths. */
|
|
1073
|
+
@keyframes neba-anim-scale {
|
|
1074
|
+
from {
|
|
1075
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1076
|
+
scale: var(--n-anim-scale, 0.8);
|
|
1077
|
+
}
|
|
1078
|
+
to {
|
|
1079
|
+
opacity: 1;
|
|
1080
|
+
scale: 1;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
.neba-anim-scale {
|
|
1085
|
+
animation-name: neba-anim-scale;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
@keyframes neba-anim-slide {
|
|
1089
|
+
from {
|
|
1090
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1091
|
+
translate: var(--n-anim-x, 0px) var(--n-anim-y, 0px);
|
|
1092
|
+
}
|
|
1093
|
+
to {
|
|
1094
|
+
opacity: 1;
|
|
1095
|
+
translate: 0 0;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
.neba-anim-slide {
|
|
1100
|
+
animation-name: neba-anim-slide;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/* Two angles rather than one, so the same keyframe covers both the quarter turn
|
|
1104
|
+
something arrives on and the endless one a badge spins through. */
|
|
1105
|
+
@keyframes neba-anim-rotate {
|
|
1106
|
+
from {
|
|
1107
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1108
|
+
rotate: var(--n-anim-angle, -180deg);
|
|
1109
|
+
}
|
|
1110
|
+
to {
|
|
1111
|
+
opacity: 1;
|
|
1112
|
+
rotate: var(--n-anim-angle-to, 0deg);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.neba-anim-rotate {
|
|
1117
|
+
animation-name: neba-anim-rotate;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/* Symmetric on purpose: a blink that ended anywhere but where it started would
|
|
1121
|
+
leave the element half drawn whenever the count ran out. */
|
|
1122
|
+
@keyframes neba-anim-blink {
|
|
1123
|
+
0%,
|
|
1124
|
+
100% {
|
|
1125
|
+
opacity: 1;
|
|
1126
|
+
}
|
|
1127
|
+
50% {
|
|
1128
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
.neba-anim-blink {
|
|
1133
|
+
animation-name: neba-anim-blink;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/*
|
|
1137
|
+
* Lighting: a light travelling around the outside of something.
|
|
1138
|
+
*
|
|
1139
|
+
* The arc is a conic gradient and what moves is its `from` angle, which is only
|
|
1140
|
+
* animatable because the angle is a registered custom property with a type. The
|
|
1141
|
+
* alternative — rotating the pseudo-element itself — swings its corners out
|
|
1142
|
+
* past the element on every quarter turn.
|
|
1143
|
+
*
|
|
1144
|
+
* `z-index: -1` inside an isolated stacking context puts the glow behind the
|
|
1145
|
+
* content but still inside the component, so it reads as light escaping from
|
|
1146
|
+
* under a sheet rather than as a border drawn around one.
|
|
1147
|
+
*/
|
|
1148
|
+
@property --neba-glow-angle {
|
|
1149
|
+
syntax: '<angle>';
|
|
1150
|
+
initial-value: 0deg;
|
|
1151
|
+
inherits: false;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
@keyframes neba-anim-lighting {
|
|
1155
|
+
to {
|
|
1156
|
+
--neba-glow-angle: 360deg;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
.neba-anim-lighting {
|
|
1161
|
+
position: relative;
|
|
1162
|
+
isolation: isolate;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.neba-anim-lighting::before {
|
|
1166
|
+
content: '';
|
|
1167
|
+
position: absolute;
|
|
1168
|
+
z-index: -1;
|
|
1169
|
+
inset: calc(-1 * var(--n-anim-glow-width, 3px));
|
|
1170
|
+
border-radius: inherit;
|
|
1171
|
+
background: conic-gradient(
|
|
1172
|
+
from var(--neba-glow-angle),
|
|
1173
|
+
transparent 0deg,
|
|
1174
|
+
var(--n-anim-glow, var(--n-accent)) var(--n-anim-glow-arc, 50deg),
|
|
1175
|
+
transparent calc(var(--n-anim-glow-arc, 50deg) * 2),
|
|
1176
|
+
transparent 360deg
|
|
1177
|
+
);
|
|
1178
|
+
filter: blur(var(--n-anim-glow-blur, 4px));
|
|
1179
|
+
animation-name: neba-anim-lighting;
|
|
1180
|
+
animation-duration: var(--n-anim-duration, 3s);
|
|
1181
|
+
animation-delay: var(--n-anim-delay, 0ms);
|
|
1182
|
+
animation-timing-function: linear;
|
|
1183
|
+
animation-iteration-count: var(--n-anim-repeat, infinite);
|
|
1184
|
+
animation-direction: var(--n-anim-direction, normal);
|
|
1185
|
+
animation-fill-mode: both;
|
|
1186
|
+
animation-play-state: var(--n-anim-state, running);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/*
|
|
1190
|
+
* Marquee: two identical copies, both moving by exactly one copy plus the gap.
|
|
1191
|
+
*
|
|
1192
|
+
* Which is the whole trick — when the first copy has travelled its own width,
|
|
1193
|
+
* the second is standing precisely where the first began, so there is no seam
|
|
1194
|
+
* and no frame where the strip is empty. A percentage `translate` resolves
|
|
1195
|
+
* against the element's own box, so neither copy has to be measured for this
|
|
1196
|
+
* to hold; measuring only ever decides how *fast* it goes.
|
|
1197
|
+
*/
|
|
1198
|
+
@keyframes neba-anim-marquee-x {
|
|
1199
|
+
from {
|
|
1200
|
+
translate: 0 0;
|
|
1201
|
+
}
|
|
1202
|
+
to {
|
|
1203
|
+
translate: calc(-100% - var(--n-anim-gap, 0px)) 0;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
@keyframes neba-anim-marquee-y {
|
|
1208
|
+
from {
|
|
1209
|
+
translate: 0 0;
|
|
1210
|
+
}
|
|
1211
|
+
to {
|
|
1212
|
+
translate: 0 calc(-100% - var(--n-anim-gap, 0px));
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.neba-marquee {
|
|
1217
|
+
display: flex;
|
|
1218
|
+
overflow: hidden;
|
|
1219
|
+
gap: var(--n-anim-gap, 0px);
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
.neba-marquee-vertical {
|
|
1223
|
+
flex-direction: column;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
.neba-marquee-track {
|
|
1227
|
+
display: flex;
|
|
1228
|
+
flex: 0 0 auto;
|
|
1229
|
+
align-items: center;
|
|
1230
|
+
gap: var(--n-anim-gap, 0px);
|
|
1231
|
+
animation-name: neba-anim-marquee-x;
|
|
1232
|
+
animation-duration: var(--n-anim-duration, 12s);
|
|
1233
|
+
animation-delay: var(--n-anim-delay, 0ms);
|
|
1234
|
+
/* Linear unless a caller insists otherwise. An eased marquee slows at both
|
|
1235
|
+
ends of a loop that has no ends, which reads as the page stuttering. */
|
|
1236
|
+
animation-timing-function: var(--n-anim-ease, linear);
|
|
1237
|
+
animation-iteration-count: var(--n-anim-repeat, infinite);
|
|
1238
|
+
animation-direction: var(--n-anim-direction, normal);
|
|
1239
|
+
animation-fill-mode: both;
|
|
1240
|
+
animation-play-state: var(--n-anim-state, running);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.neba-marquee-vertical .neba-marquee-track {
|
|
1244
|
+
flex-direction: column;
|
|
1245
|
+
animation-name: neba-anim-marquee-y;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
.neba-marquee[data-pause-on-hover]:hover .neba-marquee-track {
|
|
1249
|
+
animation-play-state: paused;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/*
|
|
1253
|
+
* Headline: one line replacing another from below.
|
|
1254
|
+
*
|
|
1255
|
+
* Every item is in the same grid cell, so the box is as tall as the tallest of
|
|
1256
|
+
* them and never resizes as the reel turns. The ones not on screen keep their
|
|
1257
|
+
* space with `visibility` rather than `display`, which is what makes that true.
|
|
1258
|
+
*/
|
|
1259
|
+
@keyframes neba-anim-headline-in {
|
|
1260
|
+
from {
|
|
1261
|
+
translate: 0 var(--n-anim-rise, 100%);
|
|
1262
|
+
opacity: 0;
|
|
1263
|
+
}
|
|
1264
|
+
to {
|
|
1265
|
+
translate: 0 0;
|
|
1266
|
+
opacity: 1;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
@keyframes neba-anim-headline-out {
|
|
1271
|
+
from {
|
|
1272
|
+
translate: 0 0;
|
|
1273
|
+
opacity: 1;
|
|
1274
|
+
}
|
|
1275
|
+
to {
|
|
1276
|
+
translate: 0 calc(-1 * var(--n-anim-rise, 100%));
|
|
1277
|
+
opacity: 0;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
.neba-headline {
|
|
1282
|
+
display: grid;
|
|
1283
|
+
overflow: hidden;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.neba-headline-item {
|
|
1287
|
+
grid-area: 1 / 1;
|
|
1288
|
+
visibility: hidden;
|
|
1289
|
+
animation-duration: var(--n-anim-duration, 480ms);
|
|
1290
|
+
animation-timing-function: var(--n-anim-ease, var(--neba-ease));
|
|
1291
|
+
animation-fill-mode: both;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
.neba-headline-item[data-state='active'] {
|
|
1295
|
+
visibility: visible;
|
|
1296
|
+
animation-name: neba-anim-headline-in;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.neba-headline-item[data-state='leaving'] {
|
|
1300
|
+
visibility: visible;
|
|
1301
|
+
animation-name: neba-anim-headline-out;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/* The block after a typewriter. `step-end` rather than a fade, because a caret
|
|
1305
|
+
that eases is a caret that looks like it is being rendered slowly. */
|
|
1306
|
+
@keyframes neba-anim-caret {
|
|
1307
|
+
0%,
|
|
1308
|
+
45% {
|
|
1309
|
+
opacity: 1;
|
|
1310
|
+
}
|
|
1311
|
+
55%,
|
|
1312
|
+
100% {
|
|
1313
|
+
opacity: 0;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
.neba-typing-caret {
|
|
1318
|
+
display: inline-block;
|
|
1319
|
+
animation: neba-anim-caret 1s step-end infinite;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
978
1322
|
/* Respect a reduced-motion preference. Both layers track the pointer, so they
|
|
979
1323
|
are motion in the sense that matters here — drop them entirely. */
|
|
980
1324
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -1014,4 +1358,39 @@
|
|
|
1014
1358
|
.neba-typing-dot {
|
|
1015
1359
|
animation-duration: 2.6s;
|
|
1016
1360
|
}
|
|
1361
|
+
|
|
1362
|
+
/* The highlight stops travelling and the placeholder pulses in place. Kept
|
|
1363
|
+
running for the same reason: a skeleton that holds still is indistinguishable
|
|
1364
|
+
from an empty box that finished loading with nothing in it. */
|
|
1365
|
+
.neba-skeleton::after {
|
|
1366
|
+
inset-inline-start: 0;
|
|
1367
|
+
inline-size: 100%;
|
|
1368
|
+
background-image: none;
|
|
1369
|
+
animation: neba-skeleton-pulse 2.4s var(--neba-ease) infinite;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
/*
|
|
1373
|
+
* The Animate components go the other way from the indicators above, and the
|
|
1374
|
+
* difference is what each of them is saying. A spinner that stops is lying
|
|
1375
|
+
* about whether anything is happening; an entrance that does not play has
|
|
1376
|
+
* still delivered its content, which is the only thing it was ever carrying.
|
|
1377
|
+
*
|
|
1378
|
+
* `animation: none` rather than a zero duration, because the shorthand also
|
|
1379
|
+
* clears `fill-mode` — and it is the fill that was holding an untriggered
|
|
1380
|
+
* element on its own first frame at `opacity: 0`. Left in place, respecting a
|
|
1381
|
+
* reader's preference would blank the page.
|
|
1382
|
+
*/
|
|
1383
|
+
.neba-anim,
|
|
1384
|
+
.neba-marquee-track,
|
|
1385
|
+
.neba-headline-item,
|
|
1386
|
+
.neba-typing-caret {
|
|
1387
|
+
animation: none;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/* The arc stops travelling and becomes an even glow. The same trade the
|
|
1391
|
+
skeleton makes: the decoration survives, the motion does not. */
|
|
1392
|
+
.neba-anim-lighting::before {
|
|
1393
|
+
background: var(--n-anim-glow, var(--n-accent));
|
|
1394
|
+
animation: none;
|
|
1395
|
+
}
|
|
1017
1396
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -129,6 +129,118 @@ export type NebaVariant = 'solid' | 'outline' | 'text';
|
|
|
129
129
|
* pressing removes one, so a flat control still answers a press without moving.
|
|
130
130
|
*/
|
|
131
131
|
export type NebaElevation = 0 | 1 | 2 | 3;
|
|
132
|
+
/**
|
|
133
|
+
* The six effects the `Animate*` components are built out of, and the six
|
|
134
|
+
* values the `transition` prop takes.
|
|
135
|
+
*
|
|
136
|
+
* They are named after what a reader sees rather than after the CSS property
|
|
137
|
+
* underneath: `zoom` and `grow` are both a change of scale, and they are two
|
|
138
|
+
* words because they are two *gestures* — one arrives from the middle of where
|
|
139
|
+
* it will end up, the other unfolds from nothing.
|
|
140
|
+
*
|
|
141
|
+
* Everything past these six is a component rather than a value. Typing, a
|
|
142
|
+
* marquee and a headline reel need to know what their children *are*, and a
|
|
143
|
+
* prop that only sets class names cannot.
|
|
144
|
+
*/
|
|
145
|
+
export type NebaAnimation = 'fade' | 'grow' | 'slide' | 'zoom' | 'rotate' | 'blink';
|
|
146
|
+
/**
|
|
147
|
+
* What makes an animation run.
|
|
148
|
+
*
|
|
149
|
+
* - `mount` — as soon as it is on the page. The default, and the only one that
|
|
150
|
+
* needs nothing from the caller.
|
|
151
|
+
* - `visible` — when it is scrolled into view. Once, unless `once` is off.
|
|
152
|
+
* - `hover` — while the pointer is on it, restarting from the beginning on each
|
|
153
|
+
* entry. Keyboard focus counts as a pointer here, or the effect would be
|
|
154
|
+
* unreachable without a mouse.
|
|
155
|
+
* - `manual` — never on its own. `play` is what runs it.
|
|
156
|
+
*/
|
|
157
|
+
export type NebaAnimateTrigger = 'mount' | 'visible' | 'hover' | 'manual';
|
|
158
|
+
/** Whether an effect brings its child in or takes it away. */
|
|
159
|
+
export type NebaAnimateMode = 'in' | 'out';
|
|
160
|
+
/**
|
|
161
|
+
* How many times an animation runs. `'infinite'` rather than `Infinity`,
|
|
162
|
+
* because it is written into CSS as that word and a caller who types the
|
|
163
|
+
* number would be surprised by which one worked.
|
|
164
|
+
*/
|
|
165
|
+
export type NebaAnimateRepeat = number | 'infinite';
|
|
166
|
+
/**
|
|
167
|
+
* The settings every `Animate*` component takes, and the reason they are one
|
|
168
|
+
* interface: a `delay` of 200 has to mean the same thing on a fade and on a
|
|
169
|
+
* marquee, exactly as a `size` of `md` means one height everywhere.
|
|
170
|
+
*
|
|
171
|
+
* Durations and delays are milliseconds — numbers, not CSS strings. A prop
|
|
172
|
+
* whose type is `string` invites `'0.4s'`, and then two components in the same
|
|
173
|
+
* screen are written in two units.
|
|
174
|
+
*/
|
|
175
|
+
export interface NebaAnimateProps {
|
|
176
|
+
/** How long one run takes, in milliseconds. */
|
|
177
|
+
duration?: number;
|
|
178
|
+
/** How long before it starts, in milliseconds. @default 0 */
|
|
179
|
+
delay?: number;
|
|
180
|
+
/** The easing curve, as CSS writes it. @default the house curve */
|
|
181
|
+
easing?: string;
|
|
182
|
+
/** How many times it runs. @default 1 */
|
|
183
|
+
repeat?: NebaAnimateRepeat;
|
|
184
|
+
/** Runs every other pass backwards, so a repeat returns instead of jumping. */
|
|
185
|
+
alternate?: boolean;
|
|
186
|
+
/** Holds the animation where it is. @default false */
|
|
187
|
+
paused?: boolean;
|
|
188
|
+
/** What starts it. @default 'mount' */
|
|
189
|
+
trigger?: NebaAnimateTrigger;
|
|
190
|
+
/** Runs it, when `trigger` is `manual`. Each `false` → `true` starts it over. */
|
|
191
|
+
play?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* With `trigger="visible"`, whether it runs only the first time. Off, it runs
|
|
194
|
+
* again every time the element comes back into view.
|
|
195
|
+
* @default true
|
|
196
|
+
*/
|
|
197
|
+
once?: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* With `trigger="visible"`, how much of the element has to be on screen
|
|
200
|
+
* before it counts as visible, from `0` to `1`.
|
|
201
|
+
* @default 0.2
|
|
202
|
+
*/
|
|
203
|
+
threshold?: number;
|
|
204
|
+
}
|
|
205
|
+
/** The options a `transition` prop takes when a bare effect name is not enough. */
|
|
206
|
+
export interface NebaTransitionOptions {
|
|
207
|
+
/** Which effect. */
|
|
208
|
+
type: NebaAnimation;
|
|
209
|
+
/** Milliseconds. */
|
|
210
|
+
duration?: number;
|
|
211
|
+
/** Milliseconds. @default 0 */
|
|
212
|
+
delay?: number;
|
|
213
|
+
/** CSS easing. @default the house curve */
|
|
214
|
+
easing?: string;
|
|
215
|
+
/** @default 1 */
|
|
216
|
+
repeat?: NebaAnimateRepeat;
|
|
217
|
+
/** Runs every other pass backwards. */
|
|
218
|
+
alternate?: boolean;
|
|
219
|
+
/** Which edge a `slide` comes from. @default 'bottom' */
|
|
220
|
+
from?: NebaSide;
|
|
221
|
+
/** How far a `slide` travels — a CSS length, or a number in pixels. */
|
|
222
|
+
distance?: number | string;
|
|
223
|
+
/** Where a `grow` or a `zoom` starts, as a multiple of its final size. */
|
|
224
|
+
scale?: number;
|
|
225
|
+
/** How far a `rotate` turns from, in degrees. */
|
|
226
|
+
angle?: number;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* An entrance animation on a component that displays something.
|
|
230
|
+
*
|
|
231
|
+
* A bare effect name is the whole of what most callers want —
|
|
232
|
+
* `transition="fade"` — and the object form is there for the rest.
|
|
233
|
+
*
|
|
234
|
+
* It runs on mount and once. Anything else — replaying on scroll, on hover, or
|
|
235
|
+
* under your own control — is what the `Animate*` components are, and any
|
|
236
|
+
* component can be wrapped in one. This prop exists so the common case does not
|
|
237
|
+
* need an extra element in the tree.
|
|
238
|
+
*
|
|
239
|
+
* It is offered on components that *display* something and on none that are
|
|
240
|
+
* pressed. A control that moves under the pointer is the one thing the design
|
|
241
|
+
* language rules out, and a `transition` on a Button would be exactly that.
|
|
242
|
+
*/
|
|
243
|
+
export type NebaTransition = NebaAnimation | NebaTransitionOptions;
|
|
132
244
|
/** Style props shared by most components; spread into their own prop types. */
|
|
133
245
|
export interface NebaStyleProps {
|
|
134
246
|
/** @default 'solid' */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neba",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A comprehensive React UI component library — buttons, fields, menus, dialogs, tables and much more — accessible and themeable, sharing one prop vocabulary and a translucent acrylic design language. ESM only, types included, dark mode built in.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -103,14 +103,14 @@
|
|
|
103
103
|
"@types/node": "^26.1.2",
|
|
104
104
|
"@types/react": "^19.2.18",
|
|
105
105
|
"@types/react-dom": "^19.2.4",
|
|
106
|
-
"@typescript-eslint/parser": "^8.
|
|
107
|
-
"@vitejs/plugin-react
|
|
106
|
+
"@typescript-eslint/parser": "^8.66.0",
|
|
107
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
108
108
|
"@vitest/browser": "^4.1.10",
|
|
109
109
|
"@vitest/browser-playwright": "^4.1.10",
|
|
110
110
|
"eslint": "^9.39.1",
|
|
111
111
|
"eslint-config-prettier": "^10.1.8",
|
|
112
112
|
"eslint-plugin-n": "^18.2.2",
|
|
113
|
-
"globals": "^17.
|
|
113
|
+
"globals": "^17.9.0",
|
|
114
114
|
"jiti": "^2.7.0",
|
|
115
115
|
"playwright": "^1.62.1",
|
|
116
116
|
"postcss": "^8.5.25",
|
|
@@ -120,9 +120,9 @@
|
|
|
120
120
|
"react-dom": "^19.2.8",
|
|
121
121
|
"tailwindcss": "^4.3.3",
|
|
122
122
|
"terser-glob": "^1.2.1",
|
|
123
|
-
"tsx": "^4.23.
|
|
124
|
-
"typescript": "^
|
|
125
|
-
"typescript-eslint": "^8.
|
|
123
|
+
"tsx": "^4.23.6",
|
|
124
|
+
"typescript": "^6.0.3",
|
|
125
|
+
"typescript-eslint": "^8.66.0",
|
|
126
126
|
"vite": "^8.2.0",
|
|
127
127
|
"vitepress": "^1.6.4",
|
|
128
128
|
"vitepress-i18n": "^1.3.5",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"vitest-browser-react": "^2.2.0"
|
|
132
132
|
},
|
|
133
133
|
"dependencies": {
|
|
134
|
-
"@base-ui/react": "^1.
|
|
134
|
+
"@base-ui/react": "^1.7.0"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
137
|
"@types/react": "^18.0.0 || ^19.0.0",
|