|
|
|
@@ -0,0 +1,379 @@
|
|
|
|
|
/* Needed for elevation to work */
|
|
|
|
|
:root {
|
|
|
|
|
--m3-util-elevation-0: none;
|
|
|
|
|
--m3-util-elevation-1:
|
|
|
|
|
/* Spot */
|
|
|
|
|
0px 1px 2px 0px rgb(var(--m3-scheme-shadow) / 0.3),
|
|
|
|
|
/* Ambient */ 0px 1px 3px 1px rgb(var(--m3-scheme-shadow) / 0.15);
|
|
|
|
|
--m3-util-elevation-2:
|
|
|
|
|
0px 1px 2px 0px rgb(var(--m3-scheme-shadow) / 0.3),
|
|
|
|
|
0px 2px 6px 2px rgb(var(--m3-scheme-shadow) / 0.15);
|
|
|
|
|
--m3-util-elevation-3:
|
|
|
|
|
0px 1px 3px 0px rgb(var(--m3-scheme-shadow) / 0.3),
|
|
|
|
|
0px 4px 8px 3px rgb(var(--m3-scheme-shadow) / 0.15);
|
|
|
|
|
--m3-util-elevation-4:
|
|
|
|
|
0px 2px 3px 0px rgb(var(--m3-scheme-shadow) / 0.3),
|
|
|
|
|
0px 6px 10px 4px rgb(var(--m3-scheme-shadow) / 0.15);
|
|
|
|
|
--m3-util-elevation-5:
|
|
|
|
|
0px 4px 4px 0px rgb(var(--m3-scheme-shadow) / 0.3),
|
|
|
|
|
0px 8px 12px 6px rgb(var(--m3-scheme-shadow) / 0.15);
|
|
|
|
|
|
|
|
|
|
/* Sizing */
|
|
|
|
|
--m3-util-bottom-offset: 0;
|
|
|
|
|
--m3-util-density: 0;
|
|
|
|
|
--m3-util-density-term: calc(var(--m3-util-density) * 0.25rem);
|
|
|
|
|
|
|
|
|
|
/* Shapes */
|
|
|
|
|
--m3-util-rounding-none: 0;
|
|
|
|
|
--m3-util-rounding-extra-small: 4px;
|
|
|
|
|
--m3-util-rounding-small: 8px;
|
|
|
|
|
--m3-util-rounding-medium: 12px;
|
|
|
|
|
--m3-util-rounding-large: 16px;
|
|
|
|
|
--m3-util-rounding-extra-large: 28px;
|
|
|
|
|
--m3-util-rounding-full: calc(infinity * 1px);
|
|
|
|
|
--m3-util-optical-centering-coefficient: 0.11;
|
|
|
|
|
|
|
|
|
|
--m3-font: Roboto, system-ui;
|
|
|
|
|
--m3-font-mono: "Google Sans Code", "Roboto Mono", monospace;
|
|
|
|
|
|
|
|
|
|
/* Expressive easing */
|
|
|
|
|
--m3-util-timing-function-fast-spatial: cubic-bezier(0.42, 1.67, 0.21, 0.9);
|
|
|
|
|
--m3-util-duration-fast-spatial: 350ms;
|
|
|
|
|
--m3-util-easing-fast-spatial: var(--m3-util-timing-function-fast-spatial)
|
|
|
|
|
var(--m3-util-duration-fast-spatial);
|
|
|
|
|
|
|
|
|
|
--m3-util-timing-function-spatial: cubic-bezier(0.38, 1.21, 0.22, 1);
|
|
|
|
|
--m3-util-duration-spatial: 500ms;
|
|
|
|
|
--m3-util-easing-spatial: var(--m3-util-timing-function-spatial) var(--m3-util-duration-spatial);
|
|
|
|
|
|
|
|
|
|
--m3-util-timing-function-slow-spatial: cubic-bezier(0.39, 1.29, 0.35, 0.98);
|
|
|
|
|
--m3-util-duration-slow-spatial: 650ms;
|
|
|
|
|
--m3-util-easing-slow-spatial: var(--m3-util-timing-function-slow-spatial)
|
|
|
|
|
var(--m3-util-duration-slow-spatial);
|
|
|
|
|
|
|
|
|
|
--m3-util-timing-function-fast: cubic-bezier(0.31, 0.94, 0.34, 1);
|
|
|
|
|
--m3-util-duration-fast: 150ms;
|
|
|
|
|
--m3-util-easing-fast: var(--m3-util-timing-function-fast) var(--m3-util-duration-fast);
|
|
|
|
|
|
|
|
|
|
--m3-util-timing-function: cubic-bezier(0.34, 0.8, 0.34, 1);
|
|
|
|
|
--m3-util-duration: 200ms;
|
|
|
|
|
--m3-util-easing: var(--m3-util-timing-function) var(--m3-util-duration);
|
|
|
|
|
|
|
|
|
|
--m3-util-timing-function-slow: cubic-bezier(0.34, 0.88, 0.34, 1);
|
|
|
|
|
--m3-util-duration-slow: 300ms;
|
|
|
|
|
--m3-util-easing-slow: var(--m3-util-timing-function-slow) var(--m3-util-duration-slow);
|
|
|
|
|
|
|
|
|
|
--m3-util-timing-function-emphasized: linear(
|
|
|
|
|
0,
|
|
|
|
|
0.034 6%,
|
|
|
|
|
0.073 9%,
|
|
|
|
|
0.126 11%,
|
|
|
|
|
0.194 13%,
|
|
|
|
|
0.273 15%,
|
|
|
|
|
0.351 16%,
|
|
|
|
|
0.541 18%,
|
|
|
|
|
0.652 20%,
|
|
|
|
|
0.755 24%,
|
|
|
|
|
0.839 30%,
|
|
|
|
|
0.91 39%,
|
|
|
|
|
0.959 53%,
|
|
|
|
|
0.989 72%,
|
|
|
|
|
1
|
|
|
|
|
);
|
|
|
|
|
--m3-util-timing-function-emphasized-accel: cubic-bezier(0.3, 0, 0.8, 0.15);
|
|
|
|
|
--m3-util-timing-function-emphasized-decel: cubic-bezier(0.05, 0.7, 0.1, 1);
|
|
|
|
|
|
|
|
|
|
/* deprecated */
|
|
|
|
|
--m3-util-curve: var(--m3-util-timing-function-emphasized);
|
|
|
|
|
--m3-util-curve-accel: var(--m3-util-timing-function-emphasized-accel);
|
|
|
|
|
--m3-util-curve-decel: var(--m3-util-timing-function-emphasized-decel);
|
|
|
|
|
|
|
|
|
|
accent-color: rgb(var(--m3-scheme-primary));
|
|
|
|
|
}
|
|
|
|
|
.m3-font-display-large,
|
|
|
|
|
.m3-font-display-medium,
|
|
|
|
|
.m3-font-display-small {
|
|
|
|
|
font-family: var(--m3-font-display, var(--m3-font));
|
|
|
|
|
}
|
|
|
|
|
.m3-font-headline-large,
|
|
|
|
|
.m3-font-headline-medium,
|
|
|
|
|
.m3-font-headline-small {
|
|
|
|
|
font-family: var(--m3-font-headline, var(--m3-font));
|
|
|
|
|
}
|
|
|
|
|
.m3-font-title-large,
|
|
|
|
|
.m3-font-title-medium,
|
|
|
|
|
.m3-font-title-small {
|
|
|
|
|
font-family: var(--m3-font-title, var(--m3-font));
|
|
|
|
|
}
|
|
|
|
|
.m3-font-label-large,
|
|
|
|
|
.m3-font-label-medium,
|
|
|
|
|
.m3-font-label-small {
|
|
|
|
|
font-family: var(--m3-font-label, var(--m3-font));
|
|
|
|
|
}
|
|
|
|
|
.m3-font-body-large,
|
|
|
|
|
.m3-font-body-medium,
|
|
|
|
|
.m3-font-body-small {
|
|
|
|
|
font-family: var(--m3-font-body, var(--m3-font));
|
|
|
|
|
}
|
|
|
|
|
/* As the largest text on the screen, display styles are reserved for short, important text or numerals. */
|
|
|
|
|
.m3-font-display-large {
|
|
|
|
|
font-size: var(--m3-font-display-large-size, 3.563rem);
|
|
|
|
|
line-height: var(--m3-font-display-large-height, 1.123);
|
|
|
|
|
letter-spacing: var(--m3-font-display-large-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-display-large-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-display-medium {
|
|
|
|
|
font-size: var(--m3-font-display-medium-size, 2.813rem);
|
|
|
|
|
line-height: var(--m3-font-display-medium-height, 1.156);
|
|
|
|
|
letter-spacing: var(--m3-font-display-medium-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-display-medium-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-display-small {
|
|
|
|
|
font-size: var(--m3-font-display-small-size, 2.25rem);
|
|
|
|
|
line-height: var(--m3-font-display-small-height, 1.222);
|
|
|
|
|
letter-spacing: var(--m3-font-display-small-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-display-small-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
/* Headlines are best-suited for short, high-emphasis text on smaller screens. */
|
|
|
|
|
.m3-font-headline-large {
|
|
|
|
|
font-size: var(--m3-font-headline-large-size, 2rem);
|
|
|
|
|
line-height: var(--m3-font-headline-large-height, 1.25);
|
|
|
|
|
letter-spacing: var(--m3-font-headline-large-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-headline-large-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-headline-medium {
|
|
|
|
|
font-size: var(--m3-font-headline-medium-size, 1.75rem);
|
|
|
|
|
line-height: var(--m3-font-headline-medium-height, 1.286);
|
|
|
|
|
letter-spacing: var(--m3-font-headline-medium-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-headline-medium-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-headline-small {
|
|
|
|
|
font-size: var(--m3-font-headline-small-size, 1.5rem);
|
|
|
|
|
line-height: var(--m3-font-headline-small-height, 1.333);
|
|
|
|
|
letter-spacing: var(--m3-font-headline-small-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-headline-small-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
/* Titles are smaller than headline styles, and should be used for medium-emphasis text that remains relatively short. */
|
|
|
|
|
.m3-font-title-large {
|
|
|
|
|
font-size: var(--m3-font-title-large-size, 1.375rem);
|
|
|
|
|
line-height: var(--m3-font-title-large-height, 1.273);
|
|
|
|
|
letter-spacing: var(--m3-font-title-large-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-title-large-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-title-medium {
|
|
|
|
|
font-size: var(--m3-font-title-medium-size, 1rem);
|
|
|
|
|
line-height: var(--m3-font-title-medium-height, 1.5);
|
|
|
|
|
letter-spacing: var(--m3-font-title-medium-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-title-medium-weight, 500);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-title-small {
|
|
|
|
|
font-size: var(--m3-font-title-small-size, 0.875rem);
|
|
|
|
|
line-height: var(--m3-font-title-small-height, 1.429);
|
|
|
|
|
letter-spacing: var(--m3-font-title-small-tracking, 0.006rem);
|
|
|
|
|
font-weight: var(--m3-font-title-small-weight, 500);
|
|
|
|
|
}
|
|
|
|
|
/* Label styles are smaller, utilitarian styles, used for things like the text inside components
|
|
|
|
|
or for very small text in the content body, such as captions. */
|
|
|
|
|
.m3-font-label-large {
|
|
|
|
|
font-size: var(--m3-font-label-large-size, 0.875rem);
|
|
|
|
|
line-height: var(--m3-font-label-large-height, 1.429);
|
|
|
|
|
letter-spacing: var(--m3-font-label-large-tracking, 0.006rem);
|
|
|
|
|
font-weight: var(--m3-font-label-large-weight, 500);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-label-medium {
|
|
|
|
|
font-size: var(--m3-font-label-medium-size, 0.75rem);
|
|
|
|
|
line-height: var(--m3-font-label-medium-height, 1.333);
|
|
|
|
|
letter-spacing: var(--m3-font-label-medium-tracking, 0.031rem);
|
|
|
|
|
font-weight: var(--m3-font-label-medium-weight, 500);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-label-small {
|
|
|
|
|
font-size: var(--m3-font-label-small-size, 0.688rem);
|
|
|
|
|
line-height: var(--m3-font-label-small-height, 1.455);
|
|
|
|
|
letter-spacing: var(--m3-font-label-small-tracking, 0.031rem);
|
|
|
|
|
font-weight: var(--m3-font-label-small-weight, 500);
|
|
|
|
|
}
|
|
|
|
|
/* Body styles are used for longer passages of text in your app. */
|
|
|
|
|
.m3-font-body-large {
|
|
|
|
|
font-size: var(--m3-font-body-large-size, 1rem);
|
|
|
|
|
line-height: var(--m3-font-body-large-height, 1.5);
|
|
|
|
|
letter-spacing: var(--m3-font-body-large-tracking, 0);
|
|
|
|
|
font-weight: var(--m3-font-body-large-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-body-medium {
|
|
|
|
|
font-size: var(--m3-font-body-medium-size, 0.875rem);
|
|
|
|
|
line-height: var(--m3-font-body-medium-height, 1.429);
|
|
|
|
|
letter-spacing: var(--m3-font-body-medium-tracking, 0.016rem);
|
|
|
|
|
font-weight: var(--m3-font-body-medium-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
.m3-font-body-small {
|
|
|
|
|
font-size: var(--m3-font-body-small-size, 0.75rem);
|
|
|
|
|
line-height: var(--m3-font-body-small-height, 1.333);
|
|
|
|
|
letter-spacing: var(--m3-font-body-small-tracking, 0.025rem);
|
|
|
|
|
font-weight: var(--m3-font-body-small-weight, 400);
|
|
|
|
|
}
|
|
|
|
|
/* Reset a few things */
|
|
|
|
|
@layer base {
|
|
|
|
|
*,
|
|
|
|
|
*::before,
|
|
|
|
|
*::after {
|
|
|
|
|
box-sizing: inherit;
|
|
|
|
|
}
|
|
|
|
|
.m3-container {
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
-webkit-tap-highlight-color: transparent;
|
|
|
|
|
}
|
|
|
|
|
.m3-container a,
|
|
|
|
|
a.m3-container {
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
}
|
|
|
|
|
.m3-container dialog,
|
|
|
|
|
dialog.m3-container {
|
|
|
|
|
margin: auto;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Emphasized easing timing function derived from this code:
|
|
|
|
|
const createBezierLUT = (points: number[][], pointCount: number = 100): number[][] => {
|
|
|
|
|
const lut: number[][] = [];
|
|
|
|
|
for (let t = 0; t < 1; t += 1 / pointCount) {
|
|
|
|
|
const a = (1 - t) * (1 - t) * (1 - t);
|
|
|
|
|
const b = (1 - t) * (1 - t) * t;
|
|
|
|
|
const c = (1 - t) * t * t;
|
|
|
|
|
const d = t * t * t;
|
|
|
|
|
const x = a * points[0][0] + 3 * b * points[1][0] + 3 * c * points[2][0] + d * points[3][0];
|
|
|
|
|
const y = a * points[0][1] + 3 * b * points[1][1] + 3 * c * points[2][1] + d * points[3][1];
|
|
|
|
|
lut.push([x, y]);
|
|
|
|
|
}
|
|
|
|
|
return lut;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const createCSSEaseOptimized = (
|
|
|
|
|
lutOptions: number[][][],
|
|
|
|
|
maxErrorThreshold: number = 0.01
|
|
|
|
|
): string => {
|
|
|
|
|
// Create the full lookup table
|
|
|
|
|
const lut = lutOptions.map((args) => createBezierLUT(args)).flat();
|
|
|
|
|
|
|
|
|
|
// Find key points using Douglas-Peucker algorithm
|
|
|
|
|
const keyPoints: number[][] = [lut[0], lut[lut.length - 1]];
|
|
|
|
|
const segments: number[][] = [[0, lut.length - 1]];
|
|
|
|
|
|
|
|
|
|
while (segments.length > 0) {
|
|
|
|
|
const [startIdx, endIdx] = segments.pop() || [0, 0];
|
|
|
|
|
let maxError = 0;
|
|
|
|
|
let maxErrorIdx = -1;
|
|
|
|
|
|
|
|
|
|
// Skip if segment is too small
|
|
|
|
|
if (endIdx - startIdx <= 1) continue;
|
|
|
|
|
|
|
|
|
|
const [startX, startY] = lut[startIdx];
|
|
|
|
|
const [endX, endY] = lut[endIdx];
|
|
|
|
|
|
|
|
|
|
// Find point with maximum error
|
|
|
|
|
for (let i = startIdx + 1; i < endIdx; i++) {
|
|
|
|
|
const [x, y] = lut[i];
|
|
|
|
|
|
|
|
|
|
// Linear interpolation
|
|
|
|
|
const t = (x - startX) / (endX - startX);
|
|
|
|
|
const interpolatedY = startY + t * (endY - startY);
|
|
|
|
|
|
|
|
|
|
const error = Math.abs(y - interpolatedY);
|
|
|
|
|
|
|
|
|
|
if (error > maxError) {
|
|
|
|
|
maxError = error;
|
|
|
|
|
maxErrorIdx = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If error exceeds threshold, add point and split segment
|
|
|
|
|
if (maxError > maxErrorThreshold) {
|
|
|
|
|
keyPoints.push(lut[maxErrorIdx]);
|
|
|
|
|
segments.push([startIdx, maxErrorIdx]);
|
|
|
|
|
segments.push([maxErrorIdx, endIdx]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort by x value
|
|
|
|
|
keyPoints.sort((a, b) => a[0] - b[0]);
|
|
|
|
|
|
|
|
|
|
// Format result using CSS linear() with explicit percentages
|
|
|
|
|
let result = "linear(";
|
|
|
|
|
|
|
|
|
|
// First point (no percentage for first point)
|
|
|
|
|
result += keyPoints[0][1].toFixed(3);
|
|
|
|
|
|
|
|
|
|
// Middle points with explicit percentages
|
|
|
|
|
for (let i = 1; i < keyPoints.length - 1; i++) {
|
|
|
|
|
const [x, y] = keyPoints[i];
|
|
|
|
|
const percentage = (x * 100).toFixed(0) + "%";
|
|
|
|
|
result += `, ${y.toFixed(3)} ${percentage}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Last point (no percentage for last point)
|
|
|
|
|
result += `, ${keyPoints[keyPoints.length - 1][1].toFixed(3)}`;
|
|
|
|
|
result += ")";
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Example usage
|
|
|
|
|
const testInput = [
|
|
|
|
|
[
|
|
|
|
|
[0, 0],
|
|
|
|
|
[0.05, 0],
|
|
|
|
|
[0.133, 0.06],
|
|
|
|
|
[0.166, 0.4],
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[0.166, 0.4],
|
|
|
|
|
[0.208, 0.82],
|
|
|
|
|
[0.25, 1],
|
|
|
|
|
[1, 1],
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Run optimized function with a more relaxed threshold for smaller size
|
|
|
|
|
const optimizedSmallResult = createCSSEaseOptimized(testInput, 0.01);
|
|
|
|
|
console.log("Optimized result (relaxed threshold 0.01):");
|
|
|
|
|
console.log(optimizedSmallResult);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
:root {
|
|
|
|
|
--m3-util-refocus: refocus-outward 0.6s cubic-bezier(0.14, 5.63, 0.4, 0.5) forwards;
|
|
|
|
|
}
|
|
|
|
|
:focus-visible:not(.focus-inset, .focus-none) {
|
|
|
|
|
animation: var(--m3-util-refocus);
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
:focus-visible:is(.focus-inset):not(.focus-none) {
|
|
|
|
|
animation: refocus-inward 0.6s cubic-bezier(0.14, 5.63, 0.4, 0.5) forwards;
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
:focus-visible.focus-none {
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
@keyframes refocus-outward {
|
|
|
|
|
0% {
|
|
|
|
|
box-shadow: 0 0 0 0px rgb(var(--m3-scheme-secondary));
|
|
|
|
|
}
|
|
|
|
|
100% {
|
|
|
|
|
box-shadow: 0 0 0 3px rgb(var(--m3-scheme-secondary));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@keyframes refocus-inward {
|
|
|
|
|
0% {
|
|
|
|
|
box-shadow: inset 0 0 0 0px rgb(var(--m3-scheme-secondary));
|
|
|
|
|
}
|
|
|
|
|
100% {
|
|
|
|
|
box-shadow: inset 0 0 0 3px rgb(var(--m3-scheme-secondary));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[placeholder]::placeholder {
|
|
|
|
|
color: rgb(var(--m3-scheme-on-background) / 0.5);
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
::selection {
|
|
|
|
|
background-color: rgb(var(--m3-scheme-tertiary-container));
|
|
|
|
|
color: rgb(var(--m3-scheme-on-tertiary-container));
|
|
|
|
|
}
|