@expressivecss/expressive 0.12.0 → 0.13.1
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/CHANGELOG.md +231 -1
- package/README.md +37 -1
- package/dist/css/expressive.css +5111 -36
- package/dist/css/expressive.css.map +1 -1
- package/dist/css/expressive.min.css +1 -1
- package/dist/css/expressive.min.css.map +1 -1
- package/dist/fonts/material-symbols-outlined.woff2 +0 -0
- package/dist/fonts/material-symbols-rounded.woff2 +0 -0
- package/dist/fonts/material-symbols-sharp.woff2 +0 -0
- package/dist/js/chunks/{chunk-HLDXZ7XB.mjs → chunk-3CLXLPYS.mjs} +2 -2
- package/dist/js/chunks/chunk-3DHK5CZU.mjs +105 -0
- package/dist/js/chunks/chunk-3DHK5CZU.mjs.map +7 -0
- package/dist/js/chunks/chunk-4PWAPV6F.mjs +7 -0
- package/dist/js/chunks/chunk-4PWAPV6F.mjs.map +7 -0
- package/dist/js/chunks/{chunk-HB6IW7QQ.mjs → chunk-55IA2XUC.mjs} +2 -2
- package/dist/js/chunks/chunk-CCWDV5CR.mjs +292 -0
- package/dist/js/chunks/chunk-CCWDV5CR.mjs.map +7 -0
- package/dist/js/chunks/chunk-DTKR54I6.mjs +270 -0
- package/dist/js/chunks/chunk-DTKR54I6.mjs.map +7 -0
- package/dist/js/chunks/chunk-GVGT6MIU.mjs +47 -0
- package/dist/js/chunks/chunk-GVGT6MIU.mjs.map +7 -0
- package/dist/js/chunks/chunk-HKT2S7VM.mjs +48 -0
- package/dist/js/chunks/chunk-HKT2S7VM.mjs.map +7 -0
- package/dist/js/chunks/chunk-K4CJCRGE.mjs +262 -0
- package/dist/js/chunks/chunk-K4CJCRGE.mjs.map +7 -0
- package/dist/js/chunks/chunk-LNCCYGPC.mjs +163 -0
- package/dist/js/chunks/chunk-LNCCYGPC.mjs.map +7 -0
- package/dist/js/chunks/chunk-NQLC3YMW.mjs +1 -0
- package/dist/js/chunks/chunk-O5XPWXIQ.mjs +406 -0
- package/dist/js/chunks/chunk-O5XPWXIQ.mjs.map +7 -0
- package/dist/js/chunks/chunk-P3G3QHII.mjs +166 -0
- package/dist/js/chunks/chunk-P3G3QHII.mjs.map +7 -0
- package/dist/js/chunks/{chunk-H2WA4XHH.mjs → chunk-PLYXLSH3.mjs} +4 -4
- package/dist/js/chunks/chunk-QKWPQK5N.mjs +179 -0
- package/dist/js/chunks/chunk-QKWPQK5N.mjs.map +7 -0
- package/dist/js/chunks/chunk-RHRQKTTX.mjs +139 -0
- package/dist/js/chunks/chunk-RHRQKTTX.mjs.map +7 -0
- package/dist/js/chunks/chunk-SPETGK25.mjs +59 -0
- package/dist/js/chunks/chunk-SPETGK25.mjs.map +7 -0
- package/dist/js/chunks/{chunk-YSBCHYXP.mjs → chunk-U2OTHOTI.mjs} +116 -12
- package/dist/js/chunks/chunk-U2OTHOTI.mjs.map +7 -0
- package/dist/js/chunks/chunk-VTLBW7QS.mjs +124 -0
- package/dist/js/chunks/chunk-VTLBW7QS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-RFZZCYVU.mjs → chunk-XGHORT7J.mjs} +2 -2
- package/dist/js/chunks/{chunk-HNFSMIBY.mjs → chunk-XH6BEEMY.mjs} +69 -16
- package/dist/js/chunks/chunk-XH6BEEMY.mjs.map +7 -0
- package/dist/js/expressive.cjs +2209 -32
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +2209 -32
- package/dist/js/expressive.js.map +4 -4
- package/dist/js/expressive.min.js +10 -10
- package/dist/js/expressive.min.js.map +4 -4
- package/dist/js/expressive.mjs +68 -20
- package/dist/js/expressive.mjs.map +1 -1
- package/dist/js/internal/behaviors/forms.mjs +1 -1
- package/dist/js/internal/components/autocomplete.mjs +2 -2
- package/dist/js/internal/components/barChart.mjs +10 -0
- package/dist/js/internal/components/barChart.mjs.map +7 -0
- package/dist/js/internal/components/chips.mjs +3 -3
- package/dist/js/internal/components/columnChart.mjs +9 -0
- package/dist/js/internal/components/columnChart.mjs.map +7 -0
- package/dist/js/internal/components/commandPalette.mjs +9 -0
- package/dist/js/internal/components/commandPalette.mjs.map +7 -0
- package/dist/js/internal/components/datepicker.mjs +3 -3
- package/dist/js/internal/components/heatmapChart.mjs +9 -0
- package/dist/js/internal/components/heatmapChart.mjs.map +7 -0
- package/dist/js/internal/components/index.mjs +65 -17
- package/dist/js/internal/components/lineChart.mjs +12 -0
- package/dist/js/internal/components/lineChart.mjs.map +7 -0
- package/dist/js/internal/components/menu.mjs +1 -1
- package/dist/js/internal/components/messageScroller.mjs +9 -0
- package/dist/js/internal/components/messageScroller.mjs.map +7 -0
- package/dist/js/internal/components/mixedChart.mjs +10 -0
- package/dist/js/internal/components/mixedChart.mjs.map +7 -0
- package/dist/js/internal/components/pieChart.mjs +9 -0
- package/dist/js/internal/components/pieChart.mjs.map +7 -0
- package/dist/js/internal/components/questionnaire.mjs +9 -0
- package/dist/js/internal/components/questionnaire.mjs.map +7 -0
- package/dist/js/internal/components/radarChart.mjs +9 -0
- package/dist/js/internal/components/radarChart.mjs.map +7 -0
- package/dist/js/internal/components/radialChart.mjs +9 -0
- package/dist/js/internal/components/radialChart.mjs.map +7 -0
- package/dist/js/internal/components/registry.mjs +23 -11
- package/dist/js/internal/components/richTextEditor.mjs +9 -0
- package/dist/js/internal/components/richTextEditor.mjs.map +7 -0
- package/dist/js/internal/components/select.mjs +2 -2
- package/dist/js/modular.mjs +68 -20
- package/dist/types/behaviors/forms.d.ts +22 -0
- package/dist/types/components/barChart.d.ts +24 -0
- package/dist/types/components/columnChart.d.ts +21 -0
- package/dist/types/components/commandPalette.d.ts +96 -0
- package/dist/types/components/heatmapChart.d.ts +49 -0
- package/dist/types/components/index.d.ts +12 -0
- package/dist/types/components/lineChart.d.ts +134 -0
- package/dist/types/components/menu.d.ts +31 -0
- package/dist/types/components/messageScroller.d.ts +111 -0
- package/dist/types/components/mixedChart.d.ts +25 -0
- package/dist/types/components/pieChart.d.ts +40 -0
- package/dist/types/components/questionnaire.d.ts +96 -0
- package/dist/types/components/radarChart.d.ts +39 -0
- package/dist/types/components/radialChart.d.ts +45 -0
- package/dist/types/components/registry.d.ts +44 -0
- package/dist/types/components/richTextEditor.d.ts +71 -0
- package/dist/types/modular.d.ts +10 -1
- package/package.json +4 -1
- package/src/sass/README.md +3 -6
- package/src/sass/abstracts/_index.scss +1 -1
- package/src/sass/abstracts/_mixins.scss +226 -0
- package/src/sass/abstracts/_variables.scss +14 -0
- package/src/sass/base/_typography.scss +45 -0
- package/src/sass/components/_accordion.scss +161 -0
- package/src/sass/components/_aura.scss +119 -0
- package/src/sass/components/_avatar.scss +86 -0
- package/src/sass/components/_bar-chart.scss +285 -0
- package/src/sass/components/_bottom-sheet.scss +1 -0
- package/src/sass/components/_button-groups.scss +13 -3
- package/src/sass/components/_cards.scss +16 -13
- package/src/sass/components/_column-chart.scss +134 -0
- package/src/sass/components/_command-palette.scss +140 -0
- package/src/sass/components/_countdown.scss +89 -0
- package/src/sass/components/_data-table.scss +188 -0
- package/src/sass/components/_dialog.scss +1 -0
- package/src/sass/components/_empty-state.scss +78 -0
- package/src/sass/components/_expanding-card.scss +3 -0
- package/src/sass/components/_heatmap-chart.scss +156 -0
- package/src/sass/components/_index.scss +27 -0
- package/src/sass/components/_kpi.scss +162 -0
- package/src/sass/components/_line-chart.scss +102 -0
- package/src/sass/components/_marquee.scss +111 -0
- package/src/sass/components/_menu.scss +10 -0
- package/src/sass/components/_message-scroller.scss +66 -0
- package/src/sass/components/_message.scss +202 -0
- package/src/sass/components/_mixed-chart.scss +157 -0
- package/src/sass/components/_navigation-bar.scss +1 -0
- package/src/sass/components/_navigation-rail.scss +9 -0
- package/src/sass/components/_pie-chart.scss +203 -0
- package/src/sass/components/_popover.scss +112 -0
- package/src/sass/components/_questionnaire.scss +144 -0
- package/src/sass/components/_radar-chart.scss +205 -0
- package/src/sass/components/_radial-chart.scss +174 -0
- package/src/sass/components/_rich-text-editor.scss +99 -0
- package/src/sass/components/_search.scss +1 -0
- package/src/sass/components/_side-sheet.scss +1 -0
- package/src/sass/components/_skeleton.scss +81 -0
- package/src/sass/components/_snackbar.scss +1 -0
- package/src/sass/components/_stat.scss +86 -0
- package/src/sass/components/_stepper.scss +190 -0
- package/src/sass/components/_timeline.scss +114 -0
- package/src/sass/components/_toolbar.scss +1 -0
- package/src/sass/components/_tooltip.scss +2 -0
- package/src/sass/components/_tree.scss +139 -0
- package/src/sass/components/forms/_drop-zone.scss +128 -0
- package/src/sass/components/forms/_index.scss +2 -0
- package/src/sass/components/forms/_input-fields.scss +133 -2
- package/src/sass/components/forms/_rating.scss +165 -0
- package/src/sass/tokens/_reference.scss +3 -15
- package/src/sass/utilities/_index.scss +2 -0
- package/src/sass/utilities/_scroll-area.scss +35 -0
- package/src/sass/utilities/_shapes.scss +164 -0
- package/dist/js/chunks/chunk-G3I5H2U3.mjs +0 -7
- package/dist/js/chunks/chunk-G3I5H2U3.mjs.map +0 -7
- package/dist/js/chunks/chunk-HNFSMIBY.mjs.map +0 -7
- package/dist/js/chunks/chunk-PSSHQWCX.mjs +0 -100
- package/dist/js/chunks/chunk-PSSHQWCX.mjs.map +0 -7
- package/dist/js/chunks/chunk-WWPAPHMA.mjs +0 -1
- package/dist/js/chunks/chunk-YSBCHYXP.mjs.map +0 -7
- /package/dist/js/chunks/{chunk-HLDXZ7XB.mjs.map → chunk-3CLXLPYS.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-HB6IW7QQ.mjs.map → chunk-55IA2XUC.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-WWPAPHMA.mjs.map → chunk-NQLC3YMW.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-H2WA4XHH.mjs.map → chunk-PLYXLSH3.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-RFZZCYVU.mjs.map → chunk-XGHORT7J.mjs.map} +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// KPI. One key figure in a card: an <article class="kpi"> holding a <dl>
|
|
4
|
+
// with a <dt> label, a <dd class="kpi-value"> and an optional
|
|
5
|
+
// <dd class="kpi-trend"> chip. The article is a card, so filled and
|
|
6
|
+
// outlined work as they do there.
|
|
7
|
+
//
|
|
8
|
+
// Optional parts, in source order after the <dl>:
|
|
9
|
+
// .kpi-icon a tonal icon box, written inside the <dt>
|
|
10
|
+
// .kpi-actions a button or menu, placed at the end of the label row
|
|
11
|
+
// a chart a sparkline .line-chart or .column-chart figure
|
|
12
|
+
// .progress a <progress> bar toward a goal
|
|
13
|
+
// <p> supporting text
|
|
14
|
+
// .kpi-footer details or links under a divider
|
|
15
|
+
//
|
|
16
|
+
// .kpi-trend takes .up or .down for the arrow and .negative when the change
|
|
17
|
+
// is bad news; .negative also turns a line, column, bar or mixed chart's
|
|
18
|
+
// first series to the error color. The arrow is decoration: say the
|
|
19
|
+
// direction in the text, as in "+12%".
|
|
20
|
+
//
|
|
21
|
+
// Tokens:
|
|
22
|
+
// --md-comp-kpi-icon-container-color primary-container
|
|
23
|
+
// --md-comp-kpi-icon-color on-primary-container
|
|
24
|
+
// --md-comp-kpi-trend-container-color secondary-container
|
|
25
|
+
// --md-comp-kpi-trend-color on-secondary-container
|
|
26
|
+
|
|
27
|
+
$_trend-charts: "line-chart", "column-chart", "bar-chart", "mixed-chart";
|
|
28
|
+
|
|
29
|
+
.kpi {
|
|
30
|
+
--md-comp-kpi-icon-container-color: var(--md-sys-color-primary-container);
|
|
31
|
+
--md-comp-kpi-icon-color: var(--md-sys-color-on-primary-container);
|
|
32
|
+
--md-comp-kpi-trend-container-color: var(--md-sys-color-secondary-container);
|
|
33
|
+
--md-comp-kpi-trend-color: var(--md-sys-color-on-secondary-container);
|
|
34
|
+
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
gap: 12px;
|
|
38
|
+
padding: var(--md-comp-card-content-padding, 16px);
|
|
39
|
+
|
|
40
|
+
> * {
|
|
41
|
+
min-width: 0;
|
|
42
|
+
margin: 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
> dl {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 8px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&:has(> .kpi-actions) > dl {
|
|
53
|
+
padding-inline-end: 40px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The card is the containing block, so the button sits in its corner
|
|
57
|
+
// without making the label row taller.
|
|
58
|
+
> .kpi-actions {
|
|
59
|
+
position: absolute;
|
|
60
|
+
inset-block-start: 8px;
|
|
61
|
+
inset-inline-end: 8px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
dt {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-basis: 100%;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 12px;
|
|
69
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
70
|
+
@include typescale("title-small");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
dd {
|
|
74
|
+
margin: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.kpi-icon {
|
|
78
|
+
display: grid;
|
|
79
|
+
flex: none;
|
|
80
|
+
place-items: center;
|
|
81
|
+
width: 40px;
|
|
82
|
+
height: 40px;
|
|
83
|
+
border-radius: 12px;
|
|
84
|
+
background-color: var(--md-comp-kpi-icon-container-color);
|
|
85
|
+
color: var(--md-comp-kpi-icon-color);
|
|
86
|
+
font-size: 24px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.kpi-value {
|
|
90
|
+
min-width: 0;
|
|
91
|
+
overflow-wrap: anywhere;
|
|
92
|
+
color: var(--md-sys-color-on-surface);
|
|
93
|
+
font-variant-numeric: tabular-nums;
|
|
94
|
+
@include typescale("headline-large");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.kpi-trend {
|
|
98
|
+
display: inline-flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 2px;
|
|
101
|
+
padding: 2px 8px;
|
|
102
|
+
border-radius: 8px;
|
|
103
|
+
background-color: var(--md-comp-kpi-trend-container-color);
|
|
104
|
+
color: var(--md-comp-kpi-trend-color);
|
|
105
|
+
font-variant-numeric: tabular-nums;
|
|
106
|
+
@include typescale("label-large");
|
|
107
|
+
|
|
108
|
+
&:is(.up, .down) {
|
|
109
|
+
padding-inline-start: 4px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&:is(.up, .down)::before {
|
|
113
|
+
content: "";
|
|
114
|
+
flex: none;
|
|
115
|
+
width: 18px;
|
|
116
|
+
height: 18px;
|
|
117
|
+
background-color: currentColor;
|
|
118
|
+
mask: $trend-arrow center / 18px no-repeat;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
&.down::before {
|
|
122
|
+
transform: rotate(180deg);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
&.negative {
|
|
126
|
+
--md-comp-kpi-trend-container-color: var(--md-sys-color-error-container);
|
|
127
|
+
--md-comp-kpi-trend-color: var(--md-sys-color-on-error-container);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
> p {
|
|
132
|
+
padding: 0;
|
|
133
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
134
|
+
@include typescale("body-medium");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
> .kpi-footer {
|
|
138
|
+
// Auto top margin keeps the footer at the bottom of a stretched card.
|
|
139
|
+
margin: auto calc(-1 * var(--md-comp-card-content-padding, 16px)) calc(-1 * var(--md-comp-card-content-padding, 16px));
|
|
140
|
+
padding: 12px var(--md-comp-card-content-padding, 16px);
|
|
141
|
+
border-top: 1px solid var(--md-sys-color-outline-variant);
|
|
142
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
143
|
+
@include typescale("body-medium");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@each $chart in $_trend-charts {
|
|
148
|
+
.kpi:has(.kpi-trend.negative) > .#{$chart} {
|
|
149
|
+
--md-comp-#{$chart}-color-1: var(--md-sys-color-error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@media (forced-colors: active) {
|
|
154
|
+
.kpi-trend {
|
|
155
|
+
outline: 1px solid CanvasText;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.kpi-trend::before {
|
|
159
|
+
forced-color-adjust: none;
|
|
160
|
+
background-color: CanvasText;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// Line chart. A <figure class="line-chart"> holds a <figcaption> and a
|
|
4
|
+
// <table> of data: the first column labels the x axis, each further column
|
|
5
|
+
// is a series named by its header cell. Without JavaScript the table shows.
|
|
6
|
+
// LineChart draws an SVG from the table and hides the table visually, so a
|
|
7
|
+
// screen reader still reads the data as a table. The plot, tooltip, labels
|
|
8
|
+
// and legend are shared with the column chart through chart().
|
|
9
|
+
//
|
|
10
|
+
// The SVG stretches to the plot (preserveAspectRatio="none") and strokes
|
|
11
|
+
// stay a constant width, so resizing needs no script. Points, the cursor
|
|
12
|
+
// and the tooltip are HTML positioned in percentages for the same reason.
|
|
13
|
+
//
|
|
14
|
+
// Modifiers: .area fills under each line, .stacked stacks each series on
|
|
15
|
+
// the ones before it and fills between them, .fade fades the line ends,
|
|
16
|
+
// .sparkline is a small chart with no axis, grid, legend or tooltip.
|
|
17
|
+
// A series header cell's classes reach its line: <th class="dashed">.
|
|
18
|
+
//
|
|
19
|
+
// Tokens:
|
|
20
|
+
// --md-comp-line-chart-height 240px (sparkline 48px)
|
|
21
|
+
// --md-comp-line-chart-line-width 3px (sparkline 2px)
|
|
22
|
+
// --md-comp-line-chart-grid-color outline-variant
|
|
23
|
+
// --md-comp-line-chart-color-1..4 primary, tertiary, secondary,
|
|
24
|
+
// on-surface-variant
|
|
25
|
+
|
|
26
|
+
@include chart("line-chart");
|
|
27
|
+
|
|
28
|
+
.line-chart {
|
|
29
|
+
--md-comp-line-chart-line-width: 3px;
|
|
30
|
+
|
|
31
|
+
&.sparkline {
|
|
32
|
+
--md-comp-line-chart-line-width: 2px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.line-chart-plot > svg {
|
|
37
|
+
position: absolute;
|
|
38
|
+
inset: 0;
|
|
39
|
+
width: 100%;
|
|
40
|
+
height: 100%;
|
|
41
|
+
overflow: visible;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.line-chart-line {
|
|
45
|
+
fill: none;
|
|
46
|
+
stroke: var(--line-chart-color);
|
|
47
|
+
stroke-width: var(--md-comp-line-chart-line-width);
|
|
48
|
+
stroke-linecap: round;
|
|
49
|
+
stroke-linejoin: round;
|
|
50
|
+
vector-effect: non-scaling-stroke;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.line-chart-series.dashed .line-chart-line {
|
|
54
|
+
stroke-dasharray: 2 8;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.line-chart-area {
|
|
58
|
+
display: none;
|
|
59
|
+
|
|
60
|
+
.line-chart:is(.area, .stacked) & {
|
|
61
|
+
display: inline;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.line-chart-series stop {
|
|
66
|
+
stop-color: var(--line-chart-color);
|
|
67
|
+
stop-opacity: 0;
|
|
68
|
+
|
|
69
|
+
&:first-child {
|
|
70
|
+
stop-opacity: 0.24;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.line-chart.fade .line-chart-plot > svg {
|
|
75
|
+
mask-image: linear-gradient(to right, transparent, #000 15% 85%, transparent);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.line-chart-cursor {
|
|
79
|
+
width: 1px;
|
|
80
|
+
background-color: var(--md-sys-color-outline);
|
|
81
|
+
|
|
82
|
+
> span {
|
|
83
|
+
position: absolute;
|
|
84
|
+
left: 0;
|
|
85
|
+
width: 10px;
|
|
86
|
+
height: 10px;
|
|
87
|
+
border: 2px solid var(--md-sys-color-surface);
|
|
88
|
+
border-radius: 50%;
|
|
89
|
+
background-color: var(--line-chart-color);
|
|
90
|
+
translate: -50% -50%;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (forced-colors: active) {
|
|
95
|
+
.line-chart-cursor {
|
|
96
|
+
background-color: CanvasText;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.line-chart-cursor > span {
|
|
100
|
+
forced-color-adjust: none;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// Marquee. A strip of logos, images or text that scrolls without end:
|
|
4
|
+
// <div class="marquee"> holding two identical <ul class="marquee-content">
|
|
5
|
+
// groups. The second is a copy that fills the gap as the first scrolls
|
|
6
|
+
// out. Mark it aria-hidden="true" and give each link or button in it
|
|
7
|
+
// tabindex="-1", so screen readers and the Tab key meet each item once and
|
|
8
|
+
// a click on the copy still works. Each group is at least as wide as the
|
|
9
|
+
// strip and spreads short content out, so one copy is always enough.
|
|
10
|
+
//
|
|
11
|
+
// Both groups move one group's length plus the gap per cycle, then jump
|
|
12
|
+
// back to where they started, which looks the same.
|
|
13
|
+
//
|
|
14
|
+
// Modifiers:
|
|
15
|
+
// .vertical scroll up; the strip is 320px tall unless the page sets a height
|
|
16
|
+
// .reverse scroll toward the inline end, or down
|
|
17
|
+
// .fade fade the items out at both edges
|
|
18
|
+
// .paused stop; toggle it from a pause button
|
|
19
|
+
//
|
|
20
|
+
// Hover or focus inside the strip also pauses it, so a link holds still
|
|
21
|
+
// while it is read or tabbed to. Horizontal strips scroll toward the inline
|
|
22
|
+
// start, so right to left pages scroll right. Reduced motion stops the
|
|
23
|
+
// scroll, drops the copy and lets the strip scroll by hand.
|
|
24
|
+
//
|
|
25
|
+
// Tokens:
|
|
26
|
+
// --md-comp-marquee-duration one cycle 20s
|
|
27
|
+
// --md-comp-marquee-gap space between items and groups 32px
|
|
28
|
+
// --md-comp-marquee-fade-size length of each edge fade (.fade) 48px
|
|
29
|
+
|
|
30
|
+
.marquee {
|
|
31
|
+
--md-comp-marquee-duration: 20s;
|
|
32
|
+
--md-comp-marquee-gap: 32px;
|
|
33
|
+
--md-comp-marquee-fade-size: 48px;
|
|
34
|
+
--_sign: 1;
|
|
35
|
+
|
|
36
|
+
display: flex;
|
|
37
|
+
gap: var(--md-comp-marquee-gap);
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
|
|
40
|
+
&:dir(rtl) {
|
|
41
|
+
--_sign: -1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.vertical {
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
height: 320px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.fade {
|
|
50
|
+
--_fade: transparent, #000 var(--md-comp-marquee-fade-size), #000 calc(100% - var(--md-comp-marquee-fade-size)), transparent;
|
|
51
|
+
mask-image: linear-gradient(to right, var(--_fade));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&.vertical.fade {
|
|
55
|
+
mask-image: linear-gradient(to bottom, var(--_fade));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.marquee-content {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex: none;
|
|
62
|
+
align-items: center;
|
|
63
|
+
justify-content: space-around;
|
|
64
|
+
gap: var(--md-comp-marquee-gap);
|
|
65
|
+
min-width: 100%;
|
|
66
|
+
margin: 0;
|
|
67
|
+
padding: 0;
|
|
68
|
+
list-style: none;
|
|
69
|
+
animation: marquee-x var(--md-comp-marquee-duration) linear infinite;
|
|
70
|
+
|
|
71
|
+
> * {
|
|
72
|
+
flex: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.vertical > & {
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
min-width: 0;
|
|
78
|
+
min-height: 100%;
|
|
79
|
+
animation-name: marquee-y;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.reverse > & {
|
|
83
|
+
animation-direction: reverse;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.marquee:is(:hover, :focus-within, .paused) > & {
|
|
87
|
+
animation-play-state: paused;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@media (prefers-reduced-motion: reduce) {
|
|
92
|
+
.marquee {
|
|
93
|
+
overflow: auto;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.marquee-content {
|
|
97
|
+
animation: none;
|
|
98
|
+
|
|
99
|
+
&[aria-hidden="true"] {
|
|
100
|
+
display: none;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@keyframes marquee-x {
|
|
106
|
+
to { translate: calc((100% + var(--md-comp-marquee-gap)) * var(--_sign) * -1) 0; }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@keyframes marquee-y {
|
|
110
|
+
to { translate: 0 calc(-100% - var(--md-comp-marquee-gap)); }
|
|
111
|
+
}
|
|
@@ -78,6 +78,7 @@ $_menu-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg
|
|
|
78
78
|
color: var(--md-comp-menu-item-label-text-color);
|
|
79
79
|
@include z-depth("2");
|
|
80
80
|
transition: border-radius 200ms ease;
|
|
81
|
+
@include glass(var(--md-comp-menu-container-color));
|
|
81
82
|
|
|
82
83
|
// The [vibrant] arms are not a second mapping - they are the statement that
|
|
83
84
|
// a menu on a vibrant surface IS a vibrant menu. Without them the foundation
|
|
@@ -360,6 +361,10 @@ $_menu-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg
|
|
|
360
361
|
filter: drop-shadow(0 3px 3px rgba(0, 0, 0, 0.14))
|
|
361
362
|
drop-shadow(0 1px 4px rgba(0, 0, 0, 0.12));
|
|
362
363
|
|
|
364
|
+
// The drop-shadow filter is the items' backdrop root, so they could only
|
|
365
|
+
// blur the menu itself. Grouped menus stay solid.
|
|
366
|
+
backdrop-filter: none;
|
|
367
|
+
|
|
363
368
|
> li:not(.divider, .optgroup, .gap, .label) {
|
|
364
369
|
padding-inline: var(--md-comp-menu-group-padding);
|
|
365
370
|
background-color: var(--md-comp-menu-container-color);
|
|
@@ -605,6 +610,11 @@ menu[id].grouped
|
|
|
605
610
|
.menu-trigger {
|
|
606
611
|
cursor: pointer;
|
|
607
612
|
|
|
613
|
+
// A context menu's trigger is a region of content, not a control.
|
|
614
|
+
&[data-context-menu] {
|
|
615
|
+
cursor: auto;
|
|
616
|
+
}
|
|
617
|
+
|
|
608
618
|
// The trigger stays in its pressed state for as long as its menu is open.
|
|
609
619
|
&[aria-expanded="true"] {
|
|
610
620
|
background-image: linear-gradient(
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// Message scroller. A chat frame around one scrolling viewport of messages
|
|
4
|
+
// and a scroll-to-latest button. The frame fills its parent, so the parent
|
|
5
|
+
// sets the height. The script owns scroll position; this partial only lays
|
|
6
|
+
// out the parts.
|
|
7
|
+
//
|
|
8
|
+
// The script turns off native scroll anchoring on the viewport and keeps the
|
|
9
|
+
// reader's place itself, so all engines behave the same. It writes
|
|
10
|
+
// --md-comp-message-scroller-spacer (blank space after the last message) so a
|
|
11
|
+
// newly anchored turn can reach the top of the viewport.
|
|
12
|
+
//
|
|
13
|
+
// Tokens:
|
|
14
|
+
// --md-comp-message-scroller-padding 16px (viewport inset)
|
|
15
|
+
// --md-comp-message-scroller-gap 16px (between messages)
|
|
16
|
+
|
|
17
|
+
.message-scroller {
|
|
18
|
+
--md-comp-message-scroller-padding: 16px;
|
|
19
|
+
--md-comp-message-scroller-gap: 16px;
|
|
20
|
+
|
|
21
|
+
position: relative;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
min-height: 0;
|
|
25
|
+
height: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.message-scroller-viewport {
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
flex: 1;
|
|
31
|
+
min-height: 0;
|
|
32
|
+
overflow-y: auto;
|
|
33
|
+
overflow-anchor: none;
|
|
34
|
+
overscroll-behavior: contain;
|
|
35
|
+
padding: var(--md-comp-message-scroller-padding);
|
|
36
|
+
padding-block-end: calc(var(--md-comp-message-scroller-padding) + var(--md-comp-message-scroller-spacer, 0px));
|
|
37
|
+
|
|
38
|
+
@include focus-visible;
|
|
39
|
+
|
|
40
|
+
> * + * {
|
|
41
|
+
margin-block-start: var(--md-comp-message-scroller-gap);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Centered over the bottom of the viewport. Inert while there is nothing
|
|
46
|
+
// below; it fades out instead of leaving a hidden tab stop.
|
|
47
|
+
.message-scroller-button {
|
|
48
|
+
position: absolute;
|
|
49
|
+
inset-block-end: 16px;
|
|
50
|
+
inset-inline: 0;
|
|
51
|
+
width: fit-content;
|
|
52
|
+
margin-inline: auto;
|
|
53
|
+
@include z-depth("2");
|
|
54
|
+
transition: opacity .15s ease-out, scale .15s ease-out;
|
|
55
|
+
|
|
56
|
+
&[inert] {
|
|
57
|
+
opacity: 0;
|
|
58
|
+
scale: .8;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media (prefers-reduced-motion: reduce) {
|
|
63
|
+
.message-scroller-button {
|
|
64
|
+
transition: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
@use "../abstracts" as *;
|
|
2
|
+
|
|
3
|
+
// Message. One message in a conversation: an optional avatar, header and
|
|
4
|
+
// footer around a single surface. The surface is every other child, normally
|
|
5
|
+
// one .message-bubble; wrap several elements in a <div> to keep them on one
|
|
6
|
+
// surface. `.end` moves the row to the sender's side.
|
|
7
|
+
//
|
|
8
|
+
// The parts are divs, not <header>/<footer>: outside sectioning content those
|
|
9
|
+
// elements become banner and contentinfo landmarks, one per message.
|
|
10
|
+
//
|
|
11
|
+
// The grid puts the avatar in the surface row, so it lines up with the bottom
|
|
12
|
+
// of the bubble and a footer below never pushes it down.
|
|
13
|
+
//
|
|
14
|
+
// Tokens:
|
|
15
|
+
// --md-comp-message-avatar-size 32px
|
|
16
|
+
// --md-comp-message-gap 8px (avatar to surface)
|
|
17
|
+
// --md-comp-message-surface-max-width 80%
|
|
18
|
+
// --md-comp-message-bubble-shape 20px
|
|
19
|
+
// --md-comp-message-bubble-grouped-shape 4px (joined corners in a group)
|
|
20
|
+
// --md-comp-message-bubble-container-color surface-container-high / end: primary-container
|
|
21
|
+
// --md-comp-message-bubble-color on-surface / end: on-primary-container
|
|
22
|
+
// --md-comp-message-group-gap 2px
|
|
23
|
+
|
|
24
|
+
.message {
|
|
25
|
+
--md-comp-message-avatar-size: 32px;
|
|
26
|
+
--md-comp-message-gap: 8px;
|
|
27
|
+
--md-comp-message-surface-max-width: 80%;
|
|
28
|
+
--md-comp-message-bubble-shape: 20px;
|
|
29
|
+
--md-comp-message-bubble-grouped-shape: 4px;
|
|
30
|
+
--md-comp-message-bubble-container-color: var(--md-sys-color-surface-container-high);
|
|
31
|
+
--md-comp-message-bubble-color: var(--md-sys-color-on-surface);
|
|
32
|
+
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
35
|
+
grid-template-areas:
|
|
36
|
+
". header"
|
|
37
|
+
"avatar surface"
|
|
38
|
+
". footer";
|
|
39
|
+
align-items: end;
|
|
40
|
+
justify-items: start;
|
|
41
|
+
color: var(--md-sys-color-on-surface);
|
|
42
|
+
|
|
43
|
+
> .message-avatar {
|
|
44
|
+
grid-area: avatar;
|
|
45
|
+
margin-inline-end: var(--md-comp-message-gap);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
> .message-header {
|
|
49
|
+
grid-area: header;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
> .message-footer {
|
|
53
|
+
grid-area: footer;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
> :not(.message-avatar, .message-header, .message-footer) {
|
|
57
|
+
grid-area: surface;
|
|
58
|
+
min-width: 0;
|
|
59
|
+
max-width: var(--md-comp-message-surface-max-width);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&.end {
|
|
63
|
+
--md-comp-message-bubble-container-color: var(--md-sys-color-primary-container);
|
|
64
|
+
--md-comp-message-bubble-color: var(--md-sys-color-on-primary-container);
|
|
65
|
+
|
|
66
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
67
|
+
grid-template-areas:
|
|
68
|
+
"header ."
|
|
69
|
+
"surface avatar"
|
|
70
|
+
"footer .";
|
|
71
|
+
justify-items: end;
|
|
72
|
+
|
|
73
|
+
> .message-avatar {
|
|
74
|
+
margin-inline: var(--md-comp-message-gap) 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// An <img>, or a box holding initials, an icon or an <img>. An empty one is a
|
|
80
|
+
// spacer that keeps earlier messages in a group in line with the last.
|
|
81
|
+
.message-avatar {
|
|
82
|
+
box-sizing: border-box;
|
|
83
|
+
display: inline-flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
width: var(--md-comp-message-avatar-size);
|
|
87
|
+
height: var(--md-comp-message-avatar-size);
|
|
88
|
+
border-radius: 50%;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
object-fit: cover;
|
|
91
|
+
@include typescale("label-medium");
|
|
92
|
+
|
|
93
|
+
&:not(img):not(:empty) {
|
|
94
|
+
background-color: var(--md-sys-color-secondary-container);
|
|
95
|
+
color: var(--md-sys-color-on-secondary-container);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
> img {
|
|
99
|
+
width: 100%;
|
|
100
|
+
height: 100%;
|
|
101
|
+
object-fit: cover;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
> #{$icon} {
|
|
105
|
+
font-size: 20px;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.message-header,
|
|
110
|
+
.message-footer {
|
|
111
|
+
display: flex;
|
|
112
|
+
flex-wrap: wrap;
|
|
113
|
+
align-items: center;
|
|
114
|
+
gap: 4px;
|
|
115
|
+
padding-inline: 12px;
|
|
116
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
117
|
+
@include typescale("label-medium");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.message-header {
|
|
121
|
+
margin-block-end: 4px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.message-footer {
|
|
125
|
+
margin-block-start: 4px;
|
|
126
|
+
|
|
127
|
+
// Icon buttons carry their own inset; drop the text inset so the first
|
|
128
|
+
// icon sits under the bubble edge rather than past it.
|
|
129
|
+
&:has(> .icon-button:first-child) {
|
|
130
|
+
padding-inline: 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.message-bubble {
|
|
135
|
+
box-sizing: border-box;
|
|
136
|
+
margin: 0;
|
|
137
|
+
padding: 10px 16px;
|
|
138
|
+
border-radius: var(--md-comp-message-bubble-shape);
|
|
139
|
+
background-color: var(--md-comp-message-bubble-container-color);
|
|
140
|
+
color: var(--md-comp-message-bubble-color);
|
|
141
|
+
overflow-wrap: anywhere;
|
|
142
|
+
@include typescale("body-large");
|
|
143
|
+
|
|
144
|
+
> * {
|
|
145
|
+
margin-block: 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
> * + * {
|
|
149
|
+
margin-block-start: 8px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Attachments and rich content: no fill, an outline-variant border.
|
|
153
|
+
&.outlined {
|
|
154
|
+
--md-comp-message-bubble-container-color: transparent;
|
|
155
|
+
--md-comp-message-bubble-color: var(--md-sys-color-on-surface);
|
|
156
|
+
|
|
157
|
+
border: 1px solid var(--md-sys-color-outline-variant);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// A bubble holding only an image or video frames it with a thin inset.
|
|
161
|
+
&:has(> :is(img, video, picture):only-child) {
|
|
162
|
+
padding: 4px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
> :is(img, video),
|
|
166
|
+
> picture > img {
|
|
167
|
+
display: block;
|
|
168
|
+
max-width: 100%;
|
|
169
|
+
height: auto;
|
|
170
|
+
border-radius: calc(var(--md-comp-message-bubble-shape) - 4px);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Consecutive messages from one sender. The bubbles join on the sender's
|
|
175
|
+
// side: inner corners shrink to the grouped shape.
|
|
176
|
+
.message-group {
|
|
177
|
+
--md-comp-message-group-gap: 2px;
|
|
178
|
+
|
|
179
|
+
display: flex;
|
|
180
|
+
flex-direction: column;
|
|
181
|
+
gap: var(--md-comp-message-group-gap);
|
|
182
|
+
|
|
183
|
+
> .message:not(.end) {
|
|
184
|
+
&:not(:first-child) .message-bubble {
|
|
185
|
+
border-start-start-radius: var(--md-comp-message-bubble-grouped-shape);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
&:not(:last-child) .message-bubble {
|
|
189
|
+
border-end-start-radius: var(--md-comp-message-bubble-grouped-shape);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
> .message.end {
|
|
194
|
+
&:not(:first-child) .message-bubble {
|
|
195
|
+
border-start-end-radius: var(--md-comp-message-bubble-grouped-shape);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
&:not(:last-child) .message-bubble {
|
|
199
|
+
border-end-end-radius: var(--md-comp-message-bubble-grouped-shape);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|