barua-ui 0.5.0 → 0.7.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 +31 -1
- package/css/components/feedback.css +9 -0
- package/css/components/marketing.css +108 -0
- package/css/components/overlays.css +17 -0
- package/css/utilities.css +74 -0
- package/dist/index.cjs +127 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +120 -6
- 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
|
|
|
@@ -144,6 +144,13 @@
|
|
|
144
144
|
box-shadow: var(--b-glass-edge);
|
|
145
145
|
pointer-events: none;
|
|
146
146
|
}
|
|
147
|
+
/* Thick material — the same glass, denser veil. For panels carrying data or
|
|
148
|
+
a form, where whatever the customer set as a wallpaper must not compete
|
|
149
|
+
with the ink. Translucency is decoration; a bounce rate is not. */
|
|
150
|
+
.b-card--glass.b-card--thick {
|
|
151
|
+
background: var(--b-material-thick-bg);
|
|
152
|
+
}
|
|
153
|
+
|
|
147
154
|
/* Glass clear — transparent, for media-rich backgrounds */
|
|
148
155
|
.b-card--glass-clear {
|
|
149
156
|
position: relative;
|
|
@@ -225,7 +232,21 @@
|
|
|
225
232
|
gap: var(--b-space-3);
|
|
226
233
|
padding: var(--b-space-3) var(--b-space-4);
|
|
227
234
|
font-size: var(--b-text-subheadline);
|
|
235
|
+
/* A row that does something is a <button>, and a <button> arrives wearing
|
|
236
|
+
the browser's own face: a grey plate, a border and centred text. Left
|
|
237
|
+
unstated, a whole list of actions renders as a column of grey slabs —
|
|
238
|
+
which is exactly what a mailbox did. Said once here, because every list
|
|
239
|
+
of actions would otherwise have to say it again. */
|
|
240
|
+
width: 100%;
|
|
241
|
+
text-align: start;
|
|
242
|
+
color: inherit;
|
|
243
|
+
background: none;
|
|
244
|
+
border: none;
|
|
228
245
|
}
|
|
246
|
+
/* Three lines and a timestamp: the mark and the time belong beside the first
|
|
247
|
+
line, not floating in the middle of a tall row. */
|
|
248
|
+
.b-list-item--top { align-items: flex-start; }
|
|
249
|
+
.b-list-item--top .b-list-item__trailing { align-items: flex-end; flex-direction: column; gap: var(--b-space-1); }
|
|
229
250
|
.b-list > .b-list-item + .b-list-item { border-top: 1px solid var(--b-separator); }
|
|
230
251
|
.b-list--inset-divider > .b-list-item + .b-list-item {
|
|
231
252
|
border-top: none;
|
|
@@ -678,6 +699,7 @@
|
|
|
678
699
|
color: currentColor;
|
|
679
700
|
}
|
|
680
701
|
.b-icon svg { width: 100%; height: 100%; }
|
|
702
|
+
.b-icon--xs { width: 0.75rem; height: 0.75rem; }
|
|
681
703
|
.b-icon--sm { width: 1rem; height: 1rem; }
|
|
682
704
|
.b-icon--lg { width: 1.5rem; height: 1.5rem; }
|
|
683
705
|
.b-icon--xl { width: 2rem; height: 2rem; }
|
|
@@ -692,6 +714,7 @@
|
|
|
692
714
|
}
|
|
693
715
|
/* iOS Settings-row size: small solid square, white glyph */
|
|
694
716
|
.b-icon-tile--sm { width: 1.85rem; height: 1.85rem; border-radius: var(--b-radius-sm); }
|
|
717
|
+
.b-icon-tile svg { width: 1.25rem; height: 1.25rem; }
|
|
695
718
|
.b-icon-tile--sm svg { width: 1.05rem; height: 1.05rem; }
|
|
696
719
|
.b-icon-tile--solid { color: #fff; background: var(--b-color-accent); }
|
|
697
720
|
.b-icon-tile--green { color: #fff; background: var(--b-color-green); }
|
|
@@ -701,7 +724,6 @@
|
|
|
701
724
|
.b-icon-tile--teal { color: #fff; background: var(--b-color-teal); }
|
|
702
725
|
.b-icon-tile--indigo { color: #fff; background: var(--b-color-indigo); }
|
|
703
726
|
.b-icon-tile--gray { color: #fff; background: var(--b-gray-1); }
|
|
704
|
-
.b-icon-tile svg { width: 1.25rem; height: 1.25rem; }
|
|
705
727
|
|
|
706
728
|
/* ---- Image ------------------------------------------------------------------------------------ */
|
|
707
729
|
.b-img { border-radius: var(--b-radius-lg); object-fit: cover; }
|
|
@@ -833,6 +855,14 @@
|
|
|
833
855
|
backdrop-filter: blur(var(--b-blur-lg)) saturate(1.1);
|
|
834
856
|
border-color: var(--b-material-neutral-edge);
|
|
835
857
|
}
|
|
858
|
+
/* …but a table of numbers is not decoration. A card that asks for the thick
|
|
859
|
+
material keeps its blur and doubles the veil, so the picture still shows at
|
|
860
|
+
the edges without competing with the ink. The veil follows the wallpaper's
|
|
861
|
+
own scheme, so it lightens on a bright picture and darkens on a dark one. */
|
|
862
|
+
.b-has-wallpaper .b-card--thick {
|
|
863
|
+
background: var(--b-material-thick-bg);
|
|
864
|
+
}
|
|
865
|
+
|
|
836
866
|
/* A panel inside glass is a fill, never a second material. */
|
|
837
867
|
.b-has-wallpaper .b-card .b-card {
|
|
838
868
|
background: var(--b-fill-quaternary);
|
|
@@ -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);
|
|
@@ -82,6 +82,114 @@
|
|
|
82
82
|
.b-hero__title { font-size: clamp(2.5rem, 7vw, 4.75rem); }
|
|
83
83
|
.b-hero__media { margin-block-start: clamp(2.5rem, 5vw, 4rem); }
|
|
84
84
|
|
|
85
|
+
/* The tile field a hero stands on.
|
|
86
|
+
|
|
87
|
+
A flat page makes a centred headline look like it is floating in milk.
|
|
88
|
+
This is the quietest possible ground: three checkerboards at different
|
|
89
|
+
scales, each barely there, masked so the pattern dissolves before it
|
|
90
|
+
reaches the text. It is drawn entirely from gradients — no image, no
|
|
91
|
+
element per square — so it costs nothing and re-tints with the theme.
|
|
92
|
+
--b-tile is the cell; --b-tile-ink is how loud the squares are. */
|
|
93
|
+
/* The tile field is absolute, so whatever holds it has to be positioned and
|
|
94
|
+
has to clip. Saying it here means no page has to remember. */
|
|
95
|
+
.b-has-tiles { position: relative; overflow: hidden; }
|
|
96
|
+
.b-tile-field {
|
|
97
|
+
position: absolute;
|
|
98
|
+
inset: 0;
|
|
99
|
+
z-index: 0;
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
--b-tile: 5.5rem;
|
|
102
|
+
/* The field paints its own ground, a shade off the page, and the squares
|
|
103
|
+
sit *lighter* on it — which is the only way the pattern is visible on a
|
|
104
|
+
white page and still barely there on a dark one. Two knobs, both
|
|
105
|
+
translucent, so whatever surface it lands on shows through. */
|
|
106
|
+
--b-tile-ground: light-dark(rgba(20, 24, 38, 0.045), rgba(255, 255, 255, 0.014));
|
|
107
|
+
--b-tile-ink: light-dark(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.03));
|
|
108
|
+
background-color: var(--b-tile-ground);
|
|
109
|
+
background-image:
|
|
110
|
+
repeating-conic-gradient(var(--b-tile-ink) 0% 25%, transparent 0% 50%),
|
|
111
|
+
repeating-conic-gradient(var(--b-tile-ink) 0% 25%, transparent 0% 50%),
|
|
112
|
+
repeating-conic-gradient(var(--b-tile-ink) 0% 25%, transparent 0% 50%);
|
|
113
|
+
background-size:
|
|
114
|
+
var(--b-tile) var(--b-tile),
|
|
115
|
+
calc(var(--b-tile) * 1.62) calc(var(--b-tile) * 1.62),
|
|
116
|
+
calc(var(--b-tile) * 2.71) calc(var(--b-tile) * 2.71);
|
|
117
|
+
background-position: 0 0, calc(var(--b-tile) * 0.5) calc(var(--b-tile) * 0.8), calc(var(--b-tile) * -0.7) calc(var(--b-tile) * 0.3);
|
|
118
|
+
/* Nothing in the middle, where the words are. */
|
|
119
|
+
-webkit-mask-image: radial-gradient(120% 85% at 50% 0%, #000 0%, transparent 72%);
|
|
120
|
+
mask-image: radial-gradient(120% 85% at 50% 0%, #000 0%, transparent 72%);
|
|
121
|
+
}
|
|
122
|
+
/* Anything that has to sit on top of it says so once. */
|
|
123
|
+
.b-tile-field ~ * { position: relative; z-index: 1; }
|
|
124
|
+
|
|
125
|
+
/* ---- Announcement: one line of news above a headline --------------------- */
|
|
126
|
+
/* The pill every product page opens with — a release, a launch, a price
|
|
127
|
+
change. It is a link, so it is an <a>; the arrow is a text mark, not an
|
|
128
|
+
icon, and it steps forward on hover the way a link should suggest travel. */
|
|
129
|
+
.b-announce {
|
|
130
|
+
display: inline-flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
gap: var(--b-space-2);
|
|
133
|
+
padding: var(--b-space-1) var(--b-space-3);
|
|
134
|
+
font-size: var(--b-text-footnote);
|
|
135
|
+
font-weight: var(--b-weight-medium);
|
|
136
|
+
color: var(--b-color-accent-text);
|
|
137
|
+
background: var(--b-color-accent-soft);
|
|
138
|
+
border: 1px solid color-mix(in srgb, var(--b-color-accent) 22%, transparent);
|
|
139
|
+
border-radius: var(--b-radius-full);
|
|
140
|
+
text-decoration: none;
|
|
141
|
+
}
|
|
142
|
+
.b-announce:hover { text-decoration: none; background: color-mix(in srgb, var(--b-color-accent) 18%, transparent); }
|
|
143
|
+
.b-announce .b-icon { width: 1rem; height: 1rem; }
|
|
144
|
+
.b-announce__go { transition: translate var(--b-duration-fast) var(--b-ease-out); }
|
|
145
|
+
.b-announce:hover .b-announce__go { translate: 2px 0; }
|
|
146
|
+
|
|
147
|
+
/* ---- Rating: borrowed credibility, stated plainly ------------------------ */
|
|
148
|
+
/* Five marks and who is vouching. The stars are the library's own star at
|
|
149
|
+
caption size; a star that was not earned carries .is-empty rather than
|
|
150
|
+
being left out, so the row is always five wide and reads as a score. */
|
|
151
|
+
.b-rating {
|
|
152
|
+
display: inline-flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
gap: var(--b-space-2);
|
|
155
|
+
font-size: var(--b-text-footnote);
|
|
156
|
+
color: var(--b-text-secondary);
|
|
157
|
+
}
|
|
158
|
+
.b-rating__stars { display: inline-flex; gap: 0.125rem; color: var(--b-color-yellow); }
|
|
159
|
+
.b-rating__stars .b-icon { width: 0.95rem; height: 0.95rem; fill: currentColor; }
|
|
160
|
+
.b-rating__stars .is-empty { color: var(--b-fill); }
|
|
161
|
+
|
|
162
|
+
/* ---- Logo wall: the companies already here ------------------------------- */
|
|
163
|
+
/* A quiet row, evenly spaced, every mark the same height whatever its
|
|
164
|
+
proportions — which is the only way a wall of logos looks deliberate
|
|
165
|
+
rather than pasted. Inline SVG on currentColor is the intended form: it
|
|
166
|
+
inherits the wall's ink and therefore survives the dark theme. Raster
|
|
167
|
+
logos get greyed instead, because a PNG cannot follow the text colour. */
|
|
168
|
+
.b-logo-wall {
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-wrap: wrap;
|
|
171
|
+
align-items: center;
|
|
172
|
+
justify-content: center;
|
|
173
|
+
gap: clamp(var(--b-space-6), 5vw, var(--b-space-12));
|
|
174
|
+
padding-block: var(--b-space-8);
|
|
175
|
+
color: var(--b-text-secondary);
|
|
176
|
+
}
|
|
177
|
+
.b-logo-wall__logo {
|
|
178
|
+
display: inline-flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
gap: var(--b-space-2);
|
|
181
|
+
height: var(--b-logo-h, 1.5rem);
|
|
182
|
+
font-size: var(--b-text-title3);
|
|
183
|
+
font-weight: var(--b-weight-semibold);
|
|
184
|
+
letter-spacing: var(--b-tracking-tight);
|
|
185
|
+
white-space: nowrap;
|
|
186
|
+
opacity: 0.7;
|
|
187
|
+
transition: opacity var(--b-duration-fast);
|
|
188
|
+
}
|
|
189
|
+
.b-logo-wall__logo:hover { opacity: 1; }
|
|
190
|
+
.b-logo-wall__logo :is(svg, img) { height: 100%; width: auto; }
|
|
191
|
+
.b-logo-wall__logo img { filter: grayscale(1); }
|
|
192
|
+
|
|
85
193
|
/* ---- Figures: a picture is furniture, so it has a shape ------------------ */
|
|
86
194
|
.b-figure { margin: 0; }
|
|
87
195
|
.b-figure__frame {
|
|
@@ -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 {
|
|
@@ -656,4 +676,58 @@
|
|
|
656
676
|
border-radius: var(--b-radius-xl);
|
|
657
677
|
box-shadow: var(--b-glass-edge), var(--b-shadow-md);
|
|
658
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
|
+
}
|
|
659
733
|
}
|