neba 1.1.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 +12 -7
- 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 +106 -0
- package/dist/components/avatar/Avatar.js +1 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/avatar/index.js +1 -0
- 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/breadcrumb/Breadcrumb.d.ts +92 -0
- package/dist/components/breadcrumb/Breadcrumb.js +1 -0
- package/dist/components/breadcrumb/index.d.ts +2 -0
- package/dist/components/breadcrumb/index.js +1 -0
- package/dist/components/chat-bubble/ChatBubble.d.ts +114 -0
- package/dist/components/chat-bubble/ChatBubble.js +1 -0
- package/dist/components/chat-bubble/index.d.ts +2 -0
- package/dist/components/chat-bubble/index.js +1 -0
- 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/otp-field/OtpField.d.ts +85 -0
- package/dist/components/otp-field/OtpField.js +1 -0
- package/dist/components/otp-field/index.d.ts +2 -0
- package/dist/components/otp-field/index.js +1 -0
- package/dist/components/panes/Panes.d.ts +78 -0
- package/dist/components/panes/Panes.js +1 -0
- package/dist/components/panes/index.d.ts +2 -0
- package/dist/components/panes/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/spoiler/Spoiler.d.ts +95 -0
- package/dist/components/spoiler/Spoiler.js +1 -0
- package/dist/components/spoiler/index.d.ts +2 -0
- package/dist/components/spoiler/index.js +1 -0
- package/dist/components/text-link/TextLink.d.ts +82 -0
- package/dist/components/text-link/TextLink.js +1 -0
- package/dist/components/text-link/index.d.ts +2 -0
- package/dist/components/text-link/index.js +1 -0
- package/dist/components/tree-view/TreeView.d.ts +115 -0
- package/dist/components/tree-view/TreeView.js +1 -0
- package/dist/components/tree-view/index.d.ts +2 -0
- package/dist/components/tree-view/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 +24 -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 +103 -0
- package/dist/internal/i18n.js +1 -0
- package/dist/internal/icons.d.ts +23 -0
- package/dist/internal/icons.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +504 -0
- package/dist/types.d.ts +112 -0
- package/package.json +14 -14
package/dist/tailwind.css
CHANGED
|
@@ -586,6 +586,40 @@
|
|
|
586
586
|
margin: 0;
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
/* ---------------------------------------------------------------------------
|
|
590
|
+
* Links
|
|
591
|
+
*
|
|
592
|
+
* `<a>` is, with `<td>`, one of the two tags a host stylesheet still styles by
|
|
593
|
+
* name — Tailwind Typography's `.prose a`, VitePress's own `.vp-doc a`, every
|
|
594
|
+
* CSS framework ever written — and always as a class plus a type, which is a
|
|
595
|
+
* specificity a one-class utility cannot reach. Table answered this by moving
|
|
596
|
+
* its cell padding inline. A link cannot: half of what it draws only exists on
|
|
597
|
+
* `:hover`, and inline styles have no `:hover`.
|
|
598
|
+
*
|
|
599
|
+
* So the selector is doubled instead. `.neba-link.neba-link` is two classes and
|
|
600
|
+
* matches nothing extra, which puts these declarations above a host's `a` rule
|
|
601
|
+
* and still below anything a caller writes with two classes of their own. Only
|
|
602
|
+
* the invariants are here — the parts of a TextLink that no prop changes. The
|
|
603
|
+
* colour and whether the line is drawn at all stay in the component, written
|
|
604
|
+
* through the same doubled class.
|
|
605
|
+
*
|
|
606
|
+
* The thickness has a `max()` floor because a hairline that lands between two
|
|
607
|
+
* device pixels is antialiased into a grey smudge: 0.055em is a real line from
|
|
608
|
+
* about 18px up, and 1px below that.
|
|
609
|
+
* ------------------------------------------------------------------------- */
|
|
610
|
+
|
|
611
|
+
.neba-link.neba-link {
|
|
612
|
+
font-weight: inherit;
|
|
613
|
+
text-decoration-thickness: max(1px, 0.055em);
|
|
614
|
+
text-underline-offset: 0.2em;
|
|
615
|
+
text-underline-position: from-font;
|
|
616
|
+
text-decoration-color: var(--n-underline);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.neba-link.neba-link:hover {
|
|
620
|
+
text-decoration-color: var(--n-underline-hover);
|
|
621
|
+
}
|
|
622
|
+
|
|
589
623
|
/* ---------------------------------------------------------------------------
|
|
590
624
|
* Grid
|
|
591
625
|
*
|
|
@@ -708,6 +742,61 @@
|
|
|
708
742
|
}
|
|
709
743
|
}
|
|
710
744
|
|
|
745
|
+
/* ---------------------------------------------------------------------------
|
|
746
|
+
* Tree guides
|
|
747
|
+
*
|
|
748
|
+
* The rail down a level of a TreeView, and — in `folder` — the elbow from that
|
|
749
|
+
* rail into every row on it.
|
|
750
|
+
*
|
|
751
|
+
* Both are drawn on the `<li>` rather than on the row inside it, and that is the
|
|
752
|
+
* whole trick: an `<li>` in a tree contains its own branch, so a rail that runs
|
|
753
|
+
* its full height keeps running past an expanded subtree and reaches the next
|
|
754
|
+
* sibling, exactly as a file manager draws it. The rail under a *last* child
|
|
755
|
+
* stops at that row's middle, which is the only thing telling the eye a branch
|
|
756
|
+
* has ended.
|
|
757
|
+
*
|
|
758
|
+
* `--n-tree-indent` and `--n-tree-row` are set inline by TreeView from its
|
|
759
|
+
* `size`. The rail sits half an indent outside the row, in the column the
|
|
760
|
+
* group's own padding opened up.
|
|
761
|
+
*
|
|
762
|
+
* This is CSS rather than Tailwind for the reason the grid is: the geometry is
|
|
763
|
+
* arithmetic on two per-instance custom properties, and the last child's rail is
|
|
764
|
+
* a different height from every other one. `[&:last-child::before]:[block-size:
|
|
765
|
+
* calc(var(--n-tree-row)/2)]` is expressible and unreadable.
|
|
766
|
+
*
|
|
767
|
+
* Everything is logical — `inset-inline-start`, `border-inline-start` — so the
|
|
768
|
+
* whole drawing mirrors under RTL without a second rule.
|
|
769
|
+
* ------------------------------------------------------------------------- */
|
|
770
|
+
|
|
771
|
+
.neba-tree-simple :where(ul[role='group']) > li::before,
|
|
772
|
+
.neba-tree-folder :where(ul[role='group']) > li::before {
|
|
773
|
+
content: '';
|
|
774
|
+
position: absolute;
|
|
775
|
+
inset-block-start: 0;
|
|
776
|
+
inset-inline-start: calc(var(--n-tree-indent, 1.25rem) / -2);
|
|
777
|
+
block-size: 100%;
|
|
778
|
+
inline-size: 0;
|
|
779
|
+
border-inline-start: 1px solid var(--neba-border);
|
|
780
|
+
pointer-events: none;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.neba-tree-folder :where(ul[role='group']) > li:last-child::before {
|
|
784
|
+
block-size: calc(var(--n-tree-row, 2rem) / 2);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/* The elbow. It stops 2px short of the row so the corner reads as a turn rather
|
|
788
|
+
than as a line running into the label. */
|
|
789
|
+
.neba-tree-folder :where(ul[role='group']) > li::after {
|
|
790
|
+
content: '';
|
|
791
|
+
position: absolute;
|
|
792
|
+
inset-block-start: calc(var(--n-tree-row, 2rem) / 2);
|
|
793
|
+
inset-inline-start: calc(var(--n-tree-indent, 1.25rem) / -2);
|
|
794
|
+
block-size: 0;
|
|
795
|
+
inline-size: calc(var(--n-tree-indent, 1.25rem) / 2 - 2px);
|
|
796
|
+
border-block-start: 1px solid var(--neba-border);
|
|
797
|
+
pointer-events: none;
|
|
798
|
+
}
|
|
799
|
+
|
|
711
800
|
/* ---------------------------------------------------------------------------
|
|
712
801
|
* Interaction light
|
|
713
802
|
*
|
|
@@ -844,6 +933,77 @@
|
|
|
844
933
|
animation-delay: calc(var(--n-i, 0) * 120ms);
|
|
845
934
|
}
|
|
846
935
|
|
|
936
|
+
/*
|
|
937
|
+
* The three dots under a message somebody is still typing.
|
|
938
|
+
*
|
|
939
|
+
* The same idea as the plates and held to the same rule: colour only, delayed
|
|
940
|
+
* per dot by its own index. Dots that bounce are what every other chat UI does,
|
|
941
|
+
* and a thread is read while this is running — something jumping in the corner
|
|
942
|
+
* of the page you are reading is the one kind of motion the design language has
|
|
943
|
+
* no time for.
|
|
944
|
+
*
|
|
945
|
+
* `currentColor` rather than a token, because a bubble's ink is white on
|
|
946
|
+
* `solid` and the page's own on the other two.
|
|
947
|
+
*/
|
|
948
|
+
@keyframes neba-typing {
|
|
949
|
+
0%,
|
|
950
|
+
60%,
|
|
951
|
+
100% {
|
|
952
|
+
background-color: color-mix(in oklab, currentColor 28%, transparent);
|
|
953
|
+
}
|
|
954
|
+
30% {
|
|
955
|
+
background-color: currentColor;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.neba-typing-dot {
|
|
960
|
+
background-color: color-mix(in oklab, currentColor 28%, transparent);
|
|
961
|
+
animation: neba-typing 1.25s var(--neba-ease) infinite;
|
|
962
|
+
animation-delay: calc(var(--n-i, 0) * 160ms);
|
|
963
|
+
}
|
|
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
|
+
|
|
847
1007
|
/* The reduced-motion stand-in for the sweep: the segment stops travelling and
|
|
848
1008
|
the whole groove pulses instead. Colour, which is the axis every other state
|
|
849
1009
|
in the library already uses. */
|
|
@@ -857,6 +1017,308 @@
|
|
|
857
1017
|
}
|
|
858
1018
|
}
|
|
859
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
|
+
|
|
860
1322
|
/* Respect a reduced-motion preference. Both layers track the pointer, so they
|
|
861
1323
|
are motion in the sense that matters here — drop them entirely. */
|
|
862
1324
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -889,4 +1351,46 @@
|
|
|
889
1351
|
.neba-plate-wave {
|
|
890
1352
|
animation-duration: 2.4s;
|
|
891
1353
|
}
|
|
1354
|
+
|
|
1355
|
+
/* Slowed rather than stopped, for the reason the indicators are: three dots
|
|
1356
|
+
holding still say the message has stalled, which is the opposite of what
|
|
1357
|
+
they are there for. */
|
|
1358
|
+
.neba-typing-dot {
|
|
1359
|
+
animation-duration: 2.6s;
|
|
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
|
+
}
|
|
892
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' */
|