neba 1.2.0 → 1.4.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 +8 -8
- 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/data-table/DataTable.d.ts +323 -0
- package/dist/components/data-table/DataTable.js +1 -0
- package/dist/components/data-table/index.d.ts +2 -0
- package/dist/components/data-table/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/empty/Empty.d.ts +69 -0
- package/dist/components/empty/Empty.js +1 -0
- package/dist/components/empty/index.d.ts +2 -0
- package/dist/components/empty/index.js +1 -0
- package/dist/components/icon/Icon.d.ts +8 -1
- package/dist/components/icon/Icon.js +1 -1
- package/dist/components/mockup/Mockup.d.ts +151 -0
- package/dist/components/mockup/Mockup.js +1 -0
- package/dist/components/mockup/index.d.ts +2 -0
- package/dist/components/mockup/index.js +1 -0
- 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 +19 -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/data-table.d.ts +170 -0
- package/dist/internal/data-table.js +1 -0
- package/dist/internal/i18n.d.ts +76 -0
- package/dist/internal/i18n.js +1 -1
- package/dist/internal/mockup.d.ts +193 -0
- package/dist/internal/mockup.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +405 -11
- package/dist/types.d.ts +112 -0
- package/package.json +12 -12
package/dist/tailwind.css
CHANGED
|
@@ -47,9 +47,18 @@
|
|
|
47
47
|
|
|
48
48
|
/* ---------------------------------------------------------------------------
|
|
49
49
|
* Light theme (default)
|
|
50
|
+
*
|
|
51
|
+
* `.light` and `[data-theme='light']` carry the same block rather than only
|
|
52
|
+
* `:root`, because forcing light has to work on a nested element too — a
|
|
53
|
+
* preview box inside a dark page has nowhere else to get these values from.
|
|
54
|
+
* Everything here that is not a colour (the radii, the motion, the grain) is
|
|
55
|
+
* identical in both themes, so re-declaring it costs a duplicate that resolves
|
|
56
|
+
* to what was inherited anyway.
|
|
50
57
|
* ------------------------------------------------------------------------- */
|
|
51
58
|
|
|
52
|
-
:root
|
|
59
|
+
:root,
|
|
60
|
+
.light,
|
|
61
|
+
[data-theme='light'] {
|
|
53
62
|
/* Neutral surfaces and content */
|
|
54
63
|
--neba-surface: oklch(100% 0 0);
|
|
55
64
|
--neba-fg: oklch(24% 0.015 262);
|
|
@@ -86,8 +95,6 @@
|
|
|
86
95
|
bottom bevel — that is what made the surface read as moulded plastic. */
|
|
87
96
|
--neba-plate-edge: rgb(255 255 255 / 0.18);
|
|
88
97
|
--neba-plate-top: rgb(255 255 255 / 0.26);
|
|
89
|
-
--neba-plate-solid: inset 0 1px 0 var(--neba-plate-top), inset 0 0 0 1px var(--neba-plate-edge);
|
|
90
|
-
--neba-plate-glass: inset 0 1px 0 var(--neba-plate-top);
|
|
91
98
|
/* Off-vertical on purpose: light falling across a sheet at an angle, rather
|
|
92
99
|
than the symmetric top-down gradient every framework ships. */
|
|
93
100
|
--neba-sheen: linear-gradient(148deg, rgb(255 255 255 / 0.13), rgb(255 255 255 / 0) 52%);
|
|
@@ -138,14 +145,6 @@
|
|
|
138
145
|
surface in space, not to advertise it. Level 4 is only reachable by
|
|
139
146
|
hovering a level-3 surface. */
|
|
140
147
|
--neba-shadow-ambient: rgb(16 24 40 / 0.13);
|
|
141
|
-
--neba-shadow-0: 0 0 #0000;
|
|
142
|
-
--neba-shadow-1: 0 1px 2px -1px var(--neba-shadow-ambient);
|
|
143
|
-
--neba-shadow-2:
|
|
144
|
-
0 2px 4px -2px var(--neba-shadow-ambient), 0 5px 12px -7px var(--neba-shadow-ambient);
|
|
145
|
-
--neba-shadow-3:
|
|
146
|
-
0 4px 8px -3px var(--neba-shadow-ambient), 0 12px 24px -11px var(--neba-shadow-ambient);
|
|
147
|
-
--neba-shadow-4:
|
|
148
|
-
0 6px 12px -4px var(--neba-shadow-ambient), 0 20px 40px -15px var(--neba-shadow-ambient);
|
|
149
148
|
|
|
150
149
|
/* Corner radius: ~45% of the control height at every step. Held just short of
|
|
151
150
|
the 50% that would make it a pill — the flat run along the top and bottom
|
|
@@ -380,6 +379,22 @@
|
|
|
380
379
|
.light,
|
|
381
380
|
[data-theme='dark'],
|
|
382
381
|
[data-theme='light'] {
|
|
382
|
+
/* The plate and the elevation ladder are two base tokens spread into shadow
|
|
383
|
+
lists, so they belong here rather than next to the values they read: left
|
|
384
|
+
in the light block they would keep the light hairline and the light ambient
|
|
385
|
+
inside a `.dark` that is not the document root. */
|
|
386
|
+
--neba-plate-solid: inset 0 1px 0 var(--neba-plate-top), inset 0 0 0 1px var(--neba-plate-edge);
|
|
387
|
+
--neba-plate-glass: inset 0 1px 0 var(--neba-plate-top);
|
|
388
|
+
|
|
389
|
+
--neba-shadow-0: 0 0 #0000;
|
|
390
|
+
--neba-shadow-1: 0 1px 2px -1px var(--neba-shadow-ambient);
|
|
391
|
+
--neba-shadow-2:
|
|
392
|
+
0 2px 4px -2px var(--neba-shadow-ambient), 0 5px 12px -7px var(--neba-shadow-ambient);
|
|
393
|
+
--neba-shadow-3:
|
|
394
|
+
0 4px 8px -3px var(--neba-shadow-ambient), 0 12px 24px -11px var(--neba-shadow-ambient);
|
|
395
|
+
--neba-shadow-4:
|
|
396
|
+
0 6px 12px -4px var(--neba-shadow-ambient), 0 20px 40px -15px var(--neba-shadow-ambient);
|
|
397
|
+
|
|
383
398
|
--neba-primary-fill: color-mix(
|
|
384
399
|
in srgb,
|
|
385
400
|
var(--neba-primary-solid) var(--neba-fill-alpha),
|
|
@@ -962,6 +977,48 @@
|
|
|
962
977
|
animation-delay: calc(var(--n-i, 0) * 160ms);
|
|
963
978
|
}
|
|
964
979
|
|
|
980
|
+
/*
|
|
981
|
+
* The highlight travelling across a placeholder.
|
|
982
|
+
*
|
|
983
|
+
* `inset-inline-start` rather than a transform, the same trade `neba-sweep`
|
|
984
|
+
* makes and for the same reason: it runs the other way under RTL without being
|
|
985
|
+
* told, and the layout pass it costs is confined to a box with nothing in it.
|
|
986
|
+
*
|
|
987
|
+
* A pseudo-element rather than a child, so a Skeleton is one element per shape
|
|
988
|
+
* and a stack of ten lines is ten nodes rather than twenty. The gradient is
|
|
989
|
+
* symmetric, so it needs no direction of its own.
|
|
990
|
+
*/
|
|
991
|
+
@keyframes neba-skeleton-sweep {
|
|
992
|
+
from {
|
|
993
|
+
inset-inline-start: -60%;
|
|
994
|
+
}
|
|
995
|
+
to {
|
|
996
|
+
inset-inline-start: 100%;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.neba-skeleton::after {
|
|
1001
|
+
content: '';
|
|
1002
|
+
position: absolute;
|
|
1003
|
+
inset-block: 0;
|
|
1004
|
+
inline-size: 60%;
|
|
1005
|
+
background-image: linear-gradient(90deg, transparent, var(--n-panel-press), transparent);
|
|
1006
|
+
animation: neba-skeleton-sweep 1.5s var(--neba-ease) infinite;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
/* The reduced-motion stand-in: the highlight stops travelling and the whole
|
|
1010
|
+
placeholder breathes instead. Colour, which is the axis every other state in
|
|
1011
|
+
the library already uses. */
|
|
1012
|
+
@keyframes neba-skeleton-pulse {
|
|
1013
|
+
0%,
|
|
1014
|
+
100% {
|
|
1015
|
+
background-color: transparent;
|
|
1016
|
+
}
|
|
1017
|
+
50% {
|
|
1018
|
+
background-color: var(--n-panel-press);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
965
1022
|
/* The reduced-motion stand-in for the sweep: the segment stops travelling and
|
|
966
1023
|
the whole groove pulses instead. Colour, which is the axis every other state
|
|
967
1024
|
in the library already uses. */
|
|
@@ -975,6 +1032,308 @@
|
|
|
975
1032
|
}
|
|
976
1033
|
}
|
|
977
1034
|
|
|
1035
|
+
/* ---------------------------------------------------------------------------
|
|
1036
|
+
* Animation
|
|
1037
|
+
*
|
|
1038
|
+
* The `Animate*` components, and the `transition` prop that shares their
|
|
1039
|
+
* effects. Everything below is real CSS for the reason the loading indicators
|
|
1040
|
+
* above are: a keyframe is not a Tailwind variant, so there is nothing to
|
|
1041
|
+
* express one with.
|
|
1042
|
+
*
|
|
1043
|
+
* The whole set is built on one idea. An effect is a single `@keyframes` that
|
|
1044
|
+
* runs from a state written entirely in `--n-anim-*` custom properties to the
|
|
1045
|
+
* element's natural one — so `src/internal/animate.ts` never generates CSS, it
|
|
1046
|
+
* only fills slots, and running an effect backwards is `animation-direction:
|
|
1047
|
+
* reverse` rather than a second keyframe. That is what makes `mode="out"` cost
|
|
1048
|
+
* nothing on all six.
|
|
1049
|
+
*
|
|
1050
|
+
* `fill-mode` is `both` throughout, which is what lets an animation that has
|
|
1051
|
+
* not been triggered yet simply sit paused on its own first frame. Without it,
|
|
1052
|
+
* an element waiting to be scrolled into view would be fully drawn and then
|
|
1053
|
+
* blink out the moment it arrived.
|
|
1054
|
+
*
|
|
1055
|
+
* This is also where the library's rule against transforms is at its narrowest.
|
|
1056
|
+
* A *control* never moves — that rule is about a button resampling its label
|
|
1057
|
+
* under the pointer, and it still holds without exception. An `Animate*` wraps
|
|
1058
|
+
* content the caller asked to have moved, and it moves it with the independent
|
|
1059
|
+
* `translate`, `scale` and `rotate` properties rather than the `transform`
|
|
1060
|
+
* shorthand, so a caller's own transform on the same element survives.
|
|
1061
|
+
* ------------------------------------------------------------------------- */
|
|
1062
|
+
|
|
1063
|
+
.neba-anim {
|
|
1064
|
+
animation-duration: var(--n-anim-duration, 320ms);
|
|
1065
|
+
animation-delay: var(--n-anim-delay, 0ms);
|
|
1066
|
+
animation-timing-function: var(--n-anim-ease, var(--neba-ease));
|
|
1067
|
+
animation-iteration-count: var(--n-anim-repeat, 1);
|
|
1068
|
+
animation-direction: var(--n-anim-direction, normal);
|
|
1069
|
+
animation-fill-mode: both;
|
|
1070
|
+
animation-play-state: var(--n-anim-state, running);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
@keyframes neba-anim-fade {
|
|
1074
|
+
from {
|
|
1075
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1076
|
+
}
|
|
1077
|
+
to {
|
|
1078
|
+
opacity: 1;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
.neba-anim-fade {
|
|
1083
|
+
animation-name: neba-anim-fade;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/* Grow and Zoom share this one: they are the same arithmetic at two strengths,
|
|
1087
|
+
separated by their defaults and by their origin rather than by their maths. */
|
|
1088
|
+
@keyframes neba-anim-scale {
|
|
1089
|
+
from {
|
|
1090
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1091
|
+
scale: var(--n-anim-scale, 0.8);
|
|
1092
|
+
}
|
|
1093
|
+
to {
|
|
1094
|
+
opacity: 1;
|
|
1095
|
+
scale: 1;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
.neba-anim-scale {
|
|
1100
|
+
animation-name: neba-anim-scale;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
@keyframes neba-anim-slide {
|
|
1104
|
+
from {
|
|
1105
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1106
|
+
translate: var(--n-anim-x, 0px) var(--n-anim-y, 0px);
|
|
1107
|
+
}
|
|
1108
|
+
to {
|
|
1109
|
+
opacity: 1;
|
|
1110
|
+
translate: 0 0;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
.neba-anim-slide {
|
|
1115
|
+
animation-name: neba-anim-slide;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/* Two angles rather than one, so the same keyframe covers both the quarter turn
|
|
1119
|
+
something arrives on and the endless one a badge spins through. */
|
|
1120
|
+
@keyframes neba-anim-rotate {
|
|
1121
|
+
from {
|
|
1122
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1123
|
+
rotate: var(--n-anim-angle, -180deg);
|
|
1124
|
+
}
|
|
1125
|
+
to {
|
|
1126
|
+
opacity: 1;
|
|
1127
|
+
rotate: var(--n-anim-angle-to, 0deg);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
.neba-anim-rotate {
|
|
1132
|
+
animation-name: neba-anim-rotate;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/* Symmetric on purpose: a blink that ended anywhere but where it started would
|
|
1136
|
+
leave the element half drawn whenever the count ran out. */
|
|
1137
|
+
@keyframes neba-anim-blink {
|
|
1138
|
+
0%,
|
|
1139
|
+
100% {
|
|
1140
|
+
opacity: 1;
|
|
1141
|
+
}
|
|
1142
|
+
50% {
|
|
1143
|
+
opacity: var(--n-anim-opacity, 0);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.neba-anim-blink {
|
|
1148
|
+
animation-name: neba-anim-blink;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/*
|
|
1152
|
+
* Lighting: a light travelling around the outside of something.
|
|
1153
|
+
*
|
|
1154
|
+
* The arc is a conic gradient and what moves is its `from` angle, which is only
|
|
1155
|
+
* animatable because the angle is a registered custom property with a type. The
|
|
1156
|
+
* alternative — rotating the pseudo-element itself — swings its corners out
|
|
1157
|
+
* past the element on every quarter turn.
|
|
1158
|
+
*
|
|
1159
|
+
* `z-index: -1` inside an isolated stacking context puts the glow behind the
|
|
1160
|
+
* content but still inside the component, so it reads as light escaping from
|
|
1161
|
+
* under a sheet rather than as a border drawn around one.
|
|
1162
|
+
*/
|
|
1163
|
+
@property --neba-glow-angle {
|
|
1164
|
+
syntax: '<angle>';
|
|
1165
|
+
initial-value: 0deg;
|
|
1166
|
+
inherits: false;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
@keyframes neba-anim-lighting {
|
|
1170
|
+
to {
|
|
1171
|
+
--neba-glow-angle: 360deg;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
.neba-anim-lighting {
|
|
1176
|
+
position: relative;
|
|
1177
|
+
isolation: isolate;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
.neba-anim-lighting::before {
|
|
1181
|
+
content: '';
|
|
1182
|
+
position: absolute;
|
|
1183
|
+
z-index: -1;
|
|
1184
|
+
inset: calc(-1 * var(--n-anim-glow-width, 3px));
|
|
1185
|
+
border-radius: inherit;
|
|
1186
|
+
background: conic-gradient(
|
|
1187
|
+
from var(--neba-glow-angle),
|
|
1188
|
+
transparent 0deg,
|
|
1189
|
+
var(--n-anim-glow, var(--n-accent)) var(--n-anim-glow-arc, 50deg),
|
|
1190
|
+
transparent calc(var(--n-anim-glow-arc, 50deg) * 2),
|
|
1191
|
+
transparent 360deg
|
|
1192
|
+
);
|
|
1193
|
+
filter: blur(var(--n-anim-glow-blur, 4px));
|
|
1194
|
+
animation-name: neba-anim-lighting;
|
|
1195
|
+
animation-duration: var(--n-anim-duration, 3s);
|
|
1196
|
+
animation-delay: var(--n-anim-delay, 0ms);
|
|
1197
|
+
animation-timing-function: linear;
|
|
1198
|
+
animation-iteration-count: var(--n-anim-repeat, infinite);
|
|
1199
|
+
animation-direction: var(--n-anim-direction, normal);
|
|
1200
|
+
animation-fill-mode: both;
|
|
1201
|
+
animation-play-state: var(--n-anim-state, running);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/*
|
|
1205
|
+
* Marquee: two identical copies, both moving by exactly one copy plus the gap.
|
|
1206
|
+
*
|
|
1207
|
+
* Which is the whole trick — when the first copy has travelled its own width,
|
|
1208
|
+
* the second is standing precisely where the first began, so there is no seam
|
|
1209
|
+
* and no frame where the strip is empty. A percentage `translate` resolves
|
|
1210
|
+
* against the element's own box, so neither copy has to be measured for this
|
|
1211
|
+
* to hold; measuring only ever decides how *fast* it goes.
|
|
1212
|
+
*/
|
|
1213
|
+
@keyframes neba-anim-marquee-x {
|
|
1214
|
+
from {
|
|
1215
|
+
translate: 0 0;
|
|
1216
|
+
}
|
|
1217
|
+
to {
|
|
1218
|
+
translate: calc(-100% - var(--n-anim-gap, 0px)) 0;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
@keyframes neba-anim-marquee-y {
|
|
1223
|
+
from {
|
|
1224
|
+
translate: 0 0;
|
|
1225
|
+
}
|
|
1226
|
+
to {
|
|
1227
|
+
translate: 0 calc(-100% - var(--n-anim-gap, 0px));
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
.neba-marquee {
|
|
1232
|
+
display: flex;
|
|
1233
|
+
overflow: hidden;
|
|
1234
|
+
gap: var(--n-anim-gap, 0px);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
.neba-marquee-vertical {
|
|
1238
|
+
flex-direction: column;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
.neba-marquee-track {
|
|
1242
|
+
display: flex;
|
|
1243
|
+
flex: 0 0 auto;
|
|
1244
|
+
align-items: center;
|
|
1245
|
+
gap: var(--n-anim-gap, 0px);
|
|
1246
|
+
animation-name: neba-anim-marquee-x;
|
|
1247
|
+
animation-duration: var(--n-anim-duration, 12s);
|
|
1248
|
+
animation-delay: var(--n-anim-delay, 0ms);
|
|
1249
|
+
/* Linear unless a caller insists otherwise. An eased marquee slows at both
|
|
1250
|
+
ends of a loop that has no ends, which reads as the page stuttering. */
|
|
1251
|
+
animation-timing-function: var(--n-anim-ease, linear);
|
|
1252
|
+
animation-iteration-count: var(--n-anim-repeat, infinite);
|
|
1253
|
+
animation-direction: var(--n-anim-direction, normal);
|
|
1254
|
+
animation-fill-mode: both;
|
|
1255
|
+
animation-play-state: var(--n-anim-state, running);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
.neba-marquee-vertical .neba-marquee-track {
|
|
1259
|
+
flex-direction: column;
|
|
1260
|
+
animation-name: neba-anim-marquee-y;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
.neba-marquee[data-pause-on-hover]:hover .neba-marquee-track {
|
|
1264
|
+
animation-play-state: paused;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
/*
|
|
1268
|
+
* Headline: one line replacing another from below.
|
|
1269
|
+
*
|
|
1270
|
+
* Every item is in the same grid cell, so the box is as tall as the tallest of
|
|
1271
|
+
* them and never resizes as the reel turns. The ones not on screen keep their
|
|
1272
|
+
* space with `visibility` rather than `display`, which is what makes that true.
|
|
1273
|
+
*/
|
|
1274
|
+
@keyframes neba-anim-headline-in {
|
|
1275
|
+
from {
|
|
1276
|
+
translate: 0 var(--n-anim-rise, 100%);
|
|
1277
|
+
opacity: 0;
|
|
1278
|
+
}
|
|
1279
|
+
to {
|
|
1280
|
+
translate: 0 0;
|
|
1281
|
+
opacity: 1;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
@keyframes neba-anim-headline-out {
|
|
1286
|
+
from {
|
|
1287
|
+
translate: 0 0;
|
|
1288
|
+
opacity: 1;
|
|
1289
|
+
}
|
|
1290
|
+
to {
|
|
1291
|
+
translate: 0 calc(-1 * var(--n-anim-rise, 100%));
|
|
1292
|
+
opacity: 0;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
.neba-headline {
|
|
1297
|
+
display: grid;
|
|
1298
|
+
overflow: hidden;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
.neba-headline-item {
|
|
1302
|
+
grid-area: 1 / 1;
|
|
1303
|
+
visibility: hidden;
|
|
1304
|
+
animation-duration: var(--n-anim-duration, 480ms);
|
|
1305
|
+
animation-timing-function: var(--n-anim-ease, var(--neba-ease));
|
|
1306
|
+
animation-fill-mode: both;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
.neba-headline-item[data-state='active'] {
|
|
1310
|
+
visibility: visible;
|
|
1311
|
+
animation-name: neba-anim-headline-in;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
.neba-headline-item[data-state='leaving'] {
|
|
1315
|
+
visibility: visible;
|
|
1316
|
+
animation-name: neba-anim-headline-out;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/* The block after a typewriter. `step-end` rather than a fade, because a caret
|
|
1320
|
+
that eases is a caret that looks like it is being rendered slowly. */
|
|
1321
|
+
@keyframes neba-anim-caret {
|
|
1322
|
+
0%,
|
|
1323
|
+
45% {
|
|
1324
|
+
opacity: 1;
|
|
1325
|
+
}
|
|
1326
|
+
55%,
|
|
1327
|
+
100% {
|
|
1328
|
+
opacity: 0;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
.neba-typing-caret {
|
|
1333
|
+
display: inline-block;
|
|
1334
|
+
animation: neba-anim-caret 1s step-end infinite;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
978
1337
|
/* Respect a reduced-motion preference. Both layers track the pointer, so they
|
|
979
1338
|
are motion in the sense that matters here — drop them entirely. */
|
|
980
1339
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -1014,4 +1373,39 @@
|
|
|
1014
1373
|
.neba-typing-dot {
|
|
1015
1374
|
animation-duration: 2.6s;
|
|
1016
1375
|
}
|
|
1376
|
+
|
|
1377
|
+
/* The highlight stops travelling and the placeholder pulses in place. Kept
|
|
1378
|
+
running for the same reason: a skeleton that holds still is indistinguishable
|
|
1379
|
+
from an empty box that finished loading with nothing in it. */
|
|
1380
|
+
.neba-skeleton::after {
|
|
1381
|
+
inset-inline-start: 0;
|
|
1382
|
+
inline-size: 100%;
|
|
1383
|
+
background-image: none;
|
|
1384
|
+
animation: neba-skeleton-pulse 2.4s var(--neba-ease) infinite;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/*
|
|
1388
|
+
* The Animate components go the other way from the indicators above, and the
|
|
1389
|
+
* difference is what each of them is saying. A spinner that stops is lying
|
|
1390
|
+
* about whether anything is happening; an entrance that does not play has
|
|
1391
|
+
* still delivered its content, which is the only thing it was ever carrying.
|
|
1392
|
+
*
|
|
1393
|
+
* `animation: none` rather than a zero duration, because the shorthand also
|
|
1394
|
+
* clears `fill-mode` — and it is the fill that was holding an untriggered
|
|
1395
|
+
* element on its own first frame at `opacity: 0`. Left in place, respecting a
|
|
1396
|
+
* reader's preference would blank the page.
|
|
1397
|
+
*/
|
|
1398
|
+
.neba-anim,
|
|
1399
|
+
.neba-marquee-track,
|
|
1400
|
+
.neba-headline-item,
|
|
1401
|
+
.neba-typing-caret {
|
|
1402
|
+
animation: none;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/* The arc stops travelling and becomes an even glow. The same trade the
|
|
1406
|
+
skeleton makes: the decoration survives, the motion does not. */
|
|
1407
|
+
.neba-anim-lighting::before {
|
|
1408
|
+
background: var(--n-anim-glow, var(--n-accent));
|
|
1409
|
+
animation: none;
|
|
1410
|
+
}
|
|
1017
1411
|
}
|
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.4.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",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"format": "prettier .",
|
|
24
24
|
"format:fix": "prettier . --write",
|
|
25
25
|
"docs:changelog": "node scripts/copy-changelog.mjs",
|
|
26
|
-
"docs:dev": "npm run
|
|
27
|
-
"docs:build": "npm run
|
|
28
|
-
"docs:serve": "npm run
|
|
26
|
+
"docs:dev": "npm run docs:changelog && vitepress dev docs",
|
|
27
|
+
"docs:build": "npm run docs:changelog && vitepress build docs",
|
|
28
|
+
"docs:serve": "npm run docs:build && vitepress serve docs",
|
|
29
29
|
"test": "vitest run",
|
|
30
30
|
"test:watch": "vitest",
|
|
31
31
|
"typecheck": "tsc --project tsconfig.prod.json --noEmit && tsc --project test/tsconfig.json && tsc --project docs/tsconfig.json"
|
|
@@ -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,18 +120,18 @@
|
|
|
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.8",
|
|
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",
|
|
129
|
-
"vitepress-sidebar": "^1.
|
|
129
|
+
"vitepress-sidebar": "^1.38.0",
|
|
130
130
|
"vitest": "^4.1.10",
|
|
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",
|