barua-ui 0.4.2 → 0.6.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/css/base.css +4 -1
- package/css/components/content.css +16 -1
- package/css/components/feedback.css +9 -0
- package/css/components/overlays.css +17 -0
- package/css/utilities.css +131 -0
- package/dist/index.cjs +306 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -4
- package/dist/index.d.ts +46 -4
- package/dist/index.js +300 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/css/base.css
CHANGED
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
min-height: 100dvh;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
img, picture, video, canvas, svg { display: block; max-width: 100%; }
|
|
32
|
+
img, picture, video, canvas, svg, iframe { display: block; max-width: 100%; }
|
|
33
|
+
/* An iframe's inset border is legacy chrome, like a button's face. A mail
|
|
34
|
+
body or an embedded document should sit on the page, not in a box. */
|
|
35
|
+
iframe { border: 0; }
|
|
33
36
|
input, button, textarea, select { font: inherit; color: inherit; letter-spacing: inherit; }
|
|
34
37
|
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
|
|
35
38
|
|
|
@@ -225,7 +225,21 @@
|
|
|
225
225
|
gap: var(--b-space-3);
|
|
226
226
|
padding: var(--b-space-3) var(--b-space-4);
|
|
227
227
|
font-size: var(--b-text-subheadline);
|
|
228
|
+
/* A row that does something is a <button>, and a <button> arrives wearing
|
|
229
|
+
the browser's own face: a grey plate, a border and centred text. Left
|
|
230
|
+
unstated, a whole list of actions renders as a column of grey slabs —
|
|
231
|
+
which is exactly what a mailbox did. Said once here, because every list
|
|
232
|
+
of actions would otherwise have to say it again. */
|
|
233
|
+
width: 100%;
|
|
234
|
+
text-align: start;
|
|
235
|
+
color: inherit;
|
|
236
|
+
background: none;
|
|
237
|
+
border: none;
|
|
228
238
|
}
|
|
239
|
+
/* Three lines and a timestamp: the mark and the time belong beside the first
|
|
240
|
+
line, not floating in the middle of a tall row. */
|
|
241
|
+
.b-list-item--top { align-items: flex-start; }
|
|
242
|
+
.b-list-item--top .b-list-item__trailing { align-items: flex-end; flex-direction: column; gap: var(--b-space-1); }
|
|
229
243
|
.b-list > .b-list-item + .b-list-item { border-top: 1px solid var(--b-separator); }
|
|
230
244
|
.b-list--inset-divider > .b-list-item + .b-list-item {
|
|
231
245
|
border-top: none;
|
|
@@ -678,6 +692,7 @@
|
|
|
678
692
|
color: currentColor;
|
|
679
693
|
}
|
|
680
694
|
.b-icon svg { width: 100%; height: 100%; }
|
|
695
|
+
.b-icon--xs { width: 0.75rem; height: 0.75rem; }
|
|
681
696
|
.b-icon--sm { width: 1rem; height: 1rem; }
|
|
682
697
|
.b-icon--lg { width: 1.5rem; height: 1.5rem; }
|
|
683
698
|
.b-icon--xl { width: 2rem; height: 2rem; }
|
|
@@ -692,6 +707,7 @@
|
|
|
692
707
|
}
|
|
693
708
|
/* iOS Settings-row size: small solid square, white glyph */
|
|
694
709
|
.b-icon-tile--sm { width: 1.85rem; height: 1.85rem; border-radius: var(--b-radius-sm); }
|
|
710
|
+
.b-icon-tile svg { width: 1.25rem; height: 1.25rem; }
|
|
695
711
|
.b-icon-tile--sm svg { width: 1.05rem; height: 1.05rem; }
|
|
696
712
|
.b-icon-tile--solid { color: #fff; background: var(--b-color-accent); }
|
|
697
713
|
.b-icon-tile--green { color: #fff; background: var(--b-color-green); }
|
|
@@ -701,7 +717,6 @@
|
|
|
701
717
|
.b-icon-tile--teal { color: #fff; background: var(--b-color-teal); }
|
|
702
718
|
.b-icon-tile--indigo { color: #fff; background: var(--b-color-indigo); }
|
|
703
719
|
.b-icon-tile--gray { color: #fff; background: var(--b-gray-1); }
|
|
704
|
-
.b-icon-tile svg { width: 1.25rem; height: 1.25rem; }
|
|
705
720
|
|
|
706
721
|
/* ---- Image ------------------------------------------------------------------------------------ */
|
|
707
722
|
.b-img { border-radius: var(--b-radius-lg); object-fit: cover; }
|
|
@@ -35,6 +35,15 @@
|
|
|
35
35
|
}
|
|
36
36
|
.b-alert__close:hover { color: var(--b-text); }
|
|
37
37
|
|
|
38
|
+
/* No opinion. The default alert is info-tinted, which turns a plain
|
|
39
|
+
"still working on it" strip blue and gives it a meaning it does not
|
|
40
|
+
have. This is the same anatomy on the neutral surface. */
|
|
41
|
+
.b-alert--neutral {
|
|
42
|
+
background: var(--b-fill-quaternary);
|
|
43
|
+
border-color: var(--b-border);
|
|
44
|
+
}
|
|
45
|
+
.b-alert--neutral .b-alert__icon { color: var(--b-text-secondary); }
|
|
46
|
+
|
|
38
47
|
.b-alert--success {
|
|
39
48
|
background: var(--b-color-success-soft);
|
|
40
49
|
border-color: color-mix(in srgb, var(--b-color-success) 30%, transparent);
|
|
@@ -158,6 +158,23 @@
|
|
|
158
158
|
.b-sheet[open] { translate: 100% 0; }
|
|
159
159
|
}
|
|
160
160
|
.b-sheet::backdrop { background: var(--b-scrim); }
|
|
161
|
+
|
|
162
|
+
/* The scrim, as a class rather than a pseudo-element.
|
|
163
|
+
`::backdrop` is drawn by the browser for a top-layer element — a native
|
|
164
|
+
<dialog> or a [popover] — and nothing else. An overlay that portals a
|
|
165
|
+
plain <div> instead, to keep a focus trap the top layer cannot give it,
|
|
166
|
+
has no backdrop to style, and every such component was repeating these
|
|
167
|
+
six declarations inline. Opacity is left to the caller, because only it
|
|
168
|
+
knows whether the overlay is arriving or leaving. */
|
|
169
|
+
.b-scrim {
|
|
170
|
+
position: fixed;
|
|
171
|
+
inset: 0;
|
|
172
|
+
z-index: var(--b-z-modal);
|
|
173
|
+
background: var(--b-scrim);
|
|
174
|
+
-webkit-backdrop-filter: blur(var(--b-blur-xs));
|
|
175
|
+
backdrop-filter: blur(var(--b-blur-xs));
|
|
176
|
+
transition: opacity var(--b-duration-normal) var(--b-ease-out);
|
|
177
|
+
}
|
|
161
178
|
.b-sheet__header {
|
|
162
179
|
display: flex;
|
|
163
180
|
align-items: center;
|
package/css/utilities.css
CHANGED
|
@@ -82,6 +82,15 @@
|
|
|
82
82
|
.b-stack--stretch { align-items: stretch; }
|
|
83
83
|
.b-stack--between { justify-content: space-between; }
|
|
84
84
|
.b-stack--wrap { flex-wrap: wrap; }
|
|
85
|
+
|
|
86
|
+
/* Main-axis placement, which the modifiers above do not cover: they set
|
|
87
|
+
align-items, so on a row they decide the cross axis. Centring a row
|
|
88
|
+
horizontally is a different instruction and needs its own word. */
|
|
89
|
+
.b-justify-start { justify-content: flex-start; }
|
|
90
|
+
.b-justify-center { justify-content: center; }
|
|
91
|
+
.b-justify-end { justify-content: flex-end; }
|
|
92
|
+
.b-justify-between { justify-content: space-between; }
|
|
93
|
+
.b-justify-around { justify-content: space-around; }
|
|
85
94
|
.b-gap-0 { --b-gap: 0; }
|
|
86
95
|
.b-gap-1 { --b-gap: var(--b-space-1); }
|
|
87
96
|
.b-gap-2 { --b-gap: var(--b-space-2); }
|
|
@@ -196,6 +205,17 @@
|
|
|
196
205
|
border-radius: var(--b-radius-lg);
|
|
197
206
|
}
|
|
198
207
|
.b-panel--plain { background: none; border: none; border-radius: 0; }
|
|
208
|
+
|
|
209
|
+
/* The list side of a list-and-detail split.
|
|
210
|
+
Full width on a phone, where it is the whole screen and a fixed column
|
|
211
|
+
would leave a band of empty glass beside it; a measured column once
|
|
212
|
+
there is room to show two things at once. This has to be a media query:
|
|
213
|
+
clamp() cannot say "fill, then stop filling", because it cannot see
|
|
214
|
+
whether anything is sitting next to it. */
|
|
215
|
+
.b-list-pane { inline-size: 100%; flex: none; }
|
|
216
|
+
@media (min-width: 768px) {
|
|
217
|
+
.b-list-pane { inline-size: clamp(20rem, 4rem + 25vw, 28rem); }
|
|
218
|
+
}
|
|
199
219
|
.b-resizable { resize: horizontal; overflow: auto; min-width: 12rem; max-width: 70%; }
|
|
200
220
|
.b-resizable--vertical { resize: vertical; min-height: 6rem; max-height: 80vh; }
|
|
201
221
|
.b-resize-handle {
|
|
@@ -599,4 +619,115 @@
|
|
|
599
619
|
@media (min-width: 768px) {
|
|
600
620
|
.b-hide-desktop { display: none !important; }
|
|
601
621
|
}
|
|
622
|
+
|
|
623
|
+
/* ---- Scroll: what a container's own position can drive ------------------
|
|
624
|
+
A container carrying data-b-scroll-geometry publishes --b-scroll-progress
|
|
625
|
+
(0–1) and --b-scroll-y, so a progress line or a parallax can be pure CSS.
|
|
626
|
+
.b-scroll-progress is that line: a hairline at the top of a scroll area
|
|
627
|
+
whose width is the distance scrolled. */
|
|
628
|
+
.b-scroll-progress {
|
|
629
|
+
position: sticky;
|
|
630
|
+
inset-block-start: 0;
|
|
631
|
+
z-index: var(--b-z-raised);
|
|
632
|
+
height: 2px;
|
|
633
|
+
width: calc(var(--b-scroll-progress, 0) * 100%);
|
|
634
|
+
background: var(--b-color-accent);
|
|
635
|
+
transition: width 80ms linear;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/* A large title that condenses as its scroll area moves — SwiftUI's
|
|
639
|
+
navigation title, on the scroll timeline so the browser drives it. Put it
|
|
640
|
+
on .b-large-title or .b-mobile-header__large-title inside the scroller. */
|
|
641
|
+
@supports (animation-timeline: scroll()) {
|
|
642
|
+
.b-scroll-condense {
|
|
643
|
+
animation: b-condense linear both;
|
|
644
|
+
animation-timeline: scroll(nearest);
|
|
645
|
+
animation-range: 0 5rem;
|
|
646
|
+
transform-origin: 0 100%;
|
|
647
|
+
}
|
|
648
|
+
@keyframes b-condense {
|
|
649
|
+
to { scale: 0.62; opacity: 0.9; }
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/* A bar over content that has moved gains its edge. */
|
|
654
|
+
.is-scrolled > .b-mobile-header,
|
|
655
|
+
.is-scrolled > .b-topnav,
|
|
656
|
+
.is-scrolled > .b-marketing-nav,
|
|
657
|
+
.b-mobile-header.is-scrolled,
|
|
658
|
+
.b-topnav.is-scrolled,
|
|
659
|
+
.b-marketing-nav.is-scrolled {
|
|
660
|
+
box-shadow: var(--b-shadow-sm);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/* data-b-visible: the entrance for browsers without a view timeline, and a
|
|
664
|
+
hook any element can use — .is-visible arrives when the threshold does. */
|
|
665
|
+
@supports not (animation-timeline: view()) {
|
|
666
|
+
.b-reveal[data-b-visible]:not(.is-visible) { opacity: 0; translate: 0 12px; }
|
|
667
|
+
.b-reveal[data-b-visible] { transition: opacity var(--b-duration-slow) var(--b-ease-out), translate var(--b-duration-slow) var(--b-ease-out); }
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* A backplate: glass put on any one element — SwiftUI's glassBackgroundEffect.
|
|
671
|
+
Blur behind, a lit top edge, a soft shadow, the system radius. */
|
|
672
|
+
.b-backplate {
|
|
673
|
+
background: var(--b-material-regular-bg);
|
|
674
|
+
-webkit-backdrop-filter: var(--b-glass);
|
|
675
|
+
backdrop-filter: var(--b-glass);
|
|
676
|
+
border-radius: var(--b-radius-xl);
|
|
677
|
+
box-shadow: var(--b-glass-edge), var(--b-shadow-md);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/* ---- Box behaviours ------------------------------------------------------
|
|
681
|
+
The handful of layout facts that Stack and Grid do not express, and that
|
|
682
|
+
every application reaches for eventually: a child that takes the room
|
|
683
|
+
left over, a child that refuses to shrink, a box allowed to be narrower
|
|
684
|
+
than its content, and the positioning contexts. Named plainly, because
|
|
685
|
+
each one says exactly what it does and nothing more. */
|
|
686
|
+
.b-flex-1 { flex: 1 1 0%; }
|
|
687
|
+
.b-shrink-0 { flex-shrink: 0; }
|
|
688
|
+
.b-grow-0 { flex-grow: 0; }
|
|
689
|
+
|
|
690
|
+
/* A flex or grid child will not go narrower than its content unless it is
|
|
691
|
+
told it may — which is why a long subject line pushes a mail row wider
|
|
692
|
+
instead of ellipsing. This is the permission. */
|
|
693
|
+
.b-min-w-0 { min-width: 0; }
|
|
694
|
+
.b-min-h-0 { min-height: 0; }
|
|
695
|
+
|
|
696
|
+
.b-w-full { inline-size: 100%; }
|
|
697
|
+
.b-h-full { block-size: 100%; }
|
|
698
|
+
.b-block { display: block; }
|
|
699
|
+
.b-inline-block { display: inline-block; }
|
|
700
|
+
.b-inline-flex { display: inline-flex; align-items: center; gap: var(--b-space-2); }
|
|
701
|
+
|
|
702
|
+
.b-relative { position: relative; }
|
|
703
|
+
.b-absolute { position: absolute; }
|
|
704
|
+
.b-sticky { position: sticky; }
|
|
705
|
+
|
|
706
|
+
.b-overflow-hidden { overflow: hidden; }
|
|
707
|
+
.b-overflow-auto { overflow: auto; }
|
|
708
|
+
.b-overflow-x-auto { overflow-x: auto; overflow-y: hidden; }
|
|
709
|
+
|
|
710
|
+
/* Figures, keys, record values: anything read character by character. */
|
|
711
|
+
.b-mono { font-family: var(--b-font-mono); font-size: 0.875em; }
|
|
712
|
+
|
|
713
|
+
/* Present to a screen reader, absent to the eye. */
|
|
714
|
+
.b-sr-only {
|
|
715
|
+
position: absolute;
|
|
716
|
+
inline-size: 1px;
|
|
717
|
+
block-size: 1px;
|
|
718
|
+
padding: 0;
|
|
719
|
+
margin: -1px;
|
|
720
|
+
overflow: hidden;
|
|
721
|
+
clip-path: inset(50%);
|
|
722
|
+
white-space: nowrap;
|
|
723
|
+
border: 0;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/* For a glyph standing in as a busy indicator. The spinner component is the
|
|
727
|
+
better answer; this is for the cases that already have an icon. */
|
|
728
|
+
.b-spin { animation: b-spin 0.8s linear infinite; }
|
|
729
|
+
@keyframes b-spin { to { transform: rotate(360deg); } }
|
|
730
|
+
@media (prefers-reduced-motion: reduce) {
|
|
731
|
+
.b-spin { animation-duration: 2.4s; }
|
|
732
|
+
}
|
|
602
733
|
}
|