Update supported browsers doc and pin browserslist (#80477)
* GDGT-3128: Pin browserslist to the versions we actually support
The documented floor (Chrome 70, Firefox 68, Edge 17, Safari 11) had drifted
far from reality. Auditing the shipped bundles turned up features that break
well above it:
- subgrid (Chrome 117), unguarded in two CSS modules
- :has() (Firefox 121), 248 occurrences; the postcss polyfill is disabled
- color-mix() (Chrome 111), including the ui/colors base palette
- toSorted/findLast (Safari 16.4) and URL.canParse (Chrome 120, Safari 17)
There are no polyfills to fall back on: core-js is not a dependency, so
preset-env injects nothing.
browserslist said "defaults", which resolves to Chrome 109 among others --
below our own floor -- so the build was targeting browsers the code breaks
on. Pin it to the audited versions instead.
The rspack swc-loaders hardcoded env.targets: ["defaults"], bypassing
package.json entirely. Dropping targets lets swc fall back to the
browserslist config, matching babel-loader and postcss.
Verified against the real postcss pipeline over all 826 CSS files. Prefix
output only improves: -webkit-backdrop-filter is now emitted (Safari needs it
through 17.6, and it was previously missing), and -webkit-background-clip is
dropped, which is safe because Chrome 120 is exactly where the unprefixed
form lands. The -moz-column-*/-o-* prefixes that go away were for Firefox
versions far below 121.
* GDGT-3128: Use the :global() function form in CSS modules
Pinning browserslist dropped `op_mini all` from the targets, and Opera Mini
was the only thing keeping postcss-preset-env on its expanded nesting
desugaring. With it gone, preset-env emits the spec-correct `:is()` form:
.editor :global .cm-panels -> :is(.editor :global) .cm-panels
That pulls `:global` inside `:is()`, where its positional "everything after
this is global" semantics no longer apply. css-loader then scoped the classes
it was meant to leave alone:
:local(.editor) .cm-panels -> :is(:local(.editor)) :local(.cm-panels)
CodeMirror renders real `.cm-editor`/`.cm-panels`/`.cm-content` elements, so
every rule in those blocks silently stopped applying -- 20 scoped selectors and
0 global in CodeMirror.module.css alone. That took out three e2e specs:
cc-typing-suggestion, native-reproductions and transforms.
The `:global()` function form binds global-ness to a selector node instead of a
position, so no amount of selector rearrangement can separate it from the class.
Verified to hold three levels deep, including under `:is()` wrapping.
Selector output is otherwise unchanged: compiling each file under the old and
new configs and comparing the post-CSS-modules selector sets gives an exact
match, except for a `::-moz-placeholder` that the browserslist pin drops on its
own (Firefox 121 has it unprefixed).
The stylelint rule catches the bare form. It also flags a top-level `:global {}`
block, which happens to work today only because a lone `:global` is a single
compound and escapes the `:is()` wrap -- one more nesting level and it breaks
the same way.
* GDGT-3128: Raise the Safari floor to 18.2 for auxclick
`auxclick` lands in Safari and iOS Safari 18.2 -- every version through 18.1
reports `n` in caniuse. There are 12 unguarded `onAuxClick` handlers in app
source (19 counting tests), so 17 was never a floor we actually met.
Chrome (55), Firefox (53) and Edge (79) are all far below their current floors,
so only Safari moves.
Side effect: `-webkit-backdrop-filter` is no longer emitted. Safari needed it
only through 17.6, so past 18.2 autoprefixer correctly drops it. The same bump
also covers scrollbar-gutter/width/color, which all wanted exactly Safari 18.2.
This commit is contained in:
@@ -28,6 +28,12 @@
|
||||
"selector-pseudo-element-colon-notation": null,
|
||||
"no-empty-source": null,
|
||||
"font-family-no-missing-generic-family-keyword": null,
|
||||
"selector-disallowed-list": [
|
||||
["/:global$/"],
|
||||
{
|
||||
"message": "Use :global(.foo) on each selector instead of a bare :global, which breaks when combined with nesting."
|
||||
}
|
||||
],
|
||||
"metabase/no-base-colors": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ redirect_from:
|
||||
|
||||
We try our best to make sure Metabase works in as many browsers as possible, but as this is the Internet, there may be little quirks from time to time in different settings. We believe Metabase works on these versions of these browsers and will attempt to fix specific bugs if any are found:
|
||||
|
||||
- Chrome (v70+)
|
||||
- Firefox (v68+)
|
||||
- Microsoft Edge (v17+)
|
||||
- Safari (v11+)
|
||||
- Chrome (v120+)
|
||||
- Firefox (v121+)
|
||||
- Microsoft Edge (v120+)
|
||||
- Safari (v18.2+)
|
||||
|
||||
Metabase may run perfectly well on older versions of these browsers or on specific browsers not listed above, but your mileage may vary. In particular, we ended support for IE11 in Metabase 0.40: it mostly still works, but you may see some unexpected behavior.
|
||||
Metabase may run on older versions of these browsers or on browsers not listed above, but your mileage may vary.
|
||||
|
||||
We recommend you use the most up-to-date browser you can.
|
||||
|
||||
@@ -1,64 +1,62 @@
|
||||
.ansiLogs {
|
||||
:global {
|
||||
.react-ansi-style-bold {
|
||||
:global(.react-ansi-style-bold) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.react-ansi-style-dim {
|
||||
:global(.react-ansi-style-dim) {
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
.react-ansi-style-italic {
|
||||
:global(.react-ansi-style-italic) {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.react-ansi-style-inverse {
|
||||
:global(.react-ansi-style-inverse) {
|
||||
color: var(--mb-color-text-primary);
|
||||
background-color: var(--mb-color-background_page-primary);
|
||||
}
|
||||
|
||||
.react-ansi-style-hidden {
|
||||
:global(.react-ansi-style-hidden) {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.react-ansi-style-underline {
|
||||
:global(.react-ansi-style-underline) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.react-ansi-style-strikethrough {
|
||||
:global(.react-ansi-style-strikethrough) {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.react-ansi-style-black {
|
||||
:global(.react-ansi-style-black) {
|
||||
color: var(--mb-color-text-primary);
|
||||
}
|
||||
|
||||
.react-ansi-style-white {
|
||||
:global(.react-ansi-style-white) {
|
||||
color: var(--mb-color-text-primary-inverse);
|
||||
}
|
||||
|
||||
.react-ansi-style-gray {
|
||||
:global(.react-ansi-style-gray) {
|
||||
color: var(--mb-color-text-disabled);
|
||||
}
|
||||
|
||||
.react-ansi-style-red {
|
||||
:global(.react-ansi-style-red) {
|
||||
color: var(--mb-color-core-red-saturated);
|
||||
}
|
||||
|
||||
.react-ansi-style-green {
|
||||
:global(.react-ansi-style-green) {
|
||||
color: var(--mb-color-core-green-saturated);
|
||||
}
|
||||
|
||||
.react-ansi-style-yellow {
|
||||
:global(.react-ansi-style-yellow) {
|
||||
color: var(--mb-color-core-yellow-saturated);
|
||||
}
|
||||
|
||||
.react-ansi-style-blue {
|
||||
:global(.react-ansi-style-blue) {
|
||||
color: var(--mb-color-core-blue-saturated);
|
||||
}
|
||||
|
||||
.react-ansi-style-purple {
|
||||
:global(.react-ansi-style-purple) {
|
||||
color: var(--mb-color-core-purple-saturated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,40 +3,39 @@
|
||||
}
|
||||
|
||||
.editor {
|
||||
:global {
|
||||
.cm-editor {
|
||||
:global(.cm-editor) {
|
||||
height: 100%;
|
||||
background: none;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.cm-focused {
|
||||
:global(.cm-focused) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* CodeMirror's search panel defaults to z-index 300, which leaks out of the
|
||||
editor and renders over surrounding components and modals. Drop it so the
|
||||
panel only stacks above the editor's own content. (metabase#73290) */
|
||||
.cm-panels {
|
||||
:global(.cm-panels) {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.cm-content {
|
||||
:global(.cm-content) {
|
||||
color: var(--mb-color-text-primary);
|
||||
background: none;
|
||||
padding-block: 8px;
|
||||
}
|
||||
|
||||
.cm-line {
|
||||
:global(.cm-line) {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.cm-gutters {
|
||||
:global(.cm-gutters) {
|
||||
background-color: var(--mb-color-background_page-secondary);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cm-gutterElement {
|
||||
:global(.cm-gutterElement) {
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
color: var(--mb-color-text-disabled);
|
||||
@@ -51,47 +50,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
.cm-activeLineGutter {
|
||||
:global(.cm-activeLineGutter) {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.cm-selectionBackground {
|
||||
:global(.cm-selectionBackground) {
|
||||
background: var(--mb-color-input-focus) !important;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.cm-selectionMatch {
|
||||
:global(.cm-selectionMatch) {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.cm-cursor {
|
||||
:global(.cm-cursor) {
|
||||
border-left-width: 1.6px;
|
||||
border-left-color: var(--mb-color-text-secondary);
|
||||
}
|
||||
|
||||
.cm-tooltip:not(.cm-tooltip-autocomplete) {
|
||||
:global(.cm-tooltip:not(.cm-tooltip-autocomplete)) {
|
||||
border: none !important;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.cm-matchingBracket {
|
||||
:global(.cm-matchingBracket) {
|
||||
background: none !important;
|
||||
outline: 0.5px solid var(--mb-color-text-disabled);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.cm-snippetField {
|
||||
:global(.cm-snippetField) {
|
||||
font-style: italic;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.cm-completionMatchedText {
|
||||
:global(.cm-completionMatchedText) {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: var(--mb-color-text-brand);
|
||||
}
|
||||
|
||||
.cm-completionDetail {
|
||||
:global(.cm-completionDetail) {
|
||||
color: var(--mb-color-text-disabled);
|
||||
font-style: normal;
|
||||
text-align: right;
|
||||
@@ -99,11 +98,11 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cm-completionIcon {
|
||||
:global(.cm-completionIcon) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cm-completionLabel {
|
||||
:global(.cm-completionLabel) {
|
||||
display: block;
|
||||
max-width: 18rem;
|
||||
overflow: hidden;
|
||||
@@ -111,7 +110,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-tooltip-autocomplete {
|
||||
:global(.cm-tooltip-autocomplete) {
|
||||
box-shadow: 0 5px 14px rgba(0, 0, 0, 0.08);
|
||||
border-radius: 4px;
|
||||
background-color: var(--mb-color-background_page-primary);
|
||||
@@ -141,13 +140,13 @@
|
||||
}
|
||||
|
||||
@supports (grid-template-columns: subgrid) {
|
||||
ul:has(.cm-completionLabel) {
|
||||
ul:has(:global(.cm-completionLabel)) {
|
||||
display: grid;
|
||||
gap: 0 1rem;
|
||||
grid-template-columns: 1fr;
|
||||
grid-auto-rows: max-content;
|
||||
|
||||
&:has(.cm-completionDetail) {
|
||||
&:has(:global(.cm-completionDetail)) {
|
||||
grid-template-columns: max-content 1fr;
|
||||
}
|
||||
|
||||
@@ -157,15 +156,14 @@
|
||||
grid-template-columns: subgrid;
|
||||
}
|
||||
|
||||
.cm-completionLabel {
|
||||
:global(.cm-completionLabel) {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.cm-completionDetail {
|
||||
:global(.cm-completionDetail) {
|
||||
grid-column: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,14 @@
|
||||
}
|
||||
|
||||
.suggestionEditor {
|
||||
:global {
|
||||
.cm-content {
|
||||
:global(.cm-content) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cm-collapsedLines {
|
||||
:global(.cm-collapsedLines) {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.suggestionEditorOnlyNew {
|
||||
background: color-mix(
|
||||
@@ -25,12 +23,10 @@
|
||||
transparent
|
||||
);
|
||||
|
||||
:global {
|
||||
.cm-gutters {
|
||||
:global(.cm-gutters) {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.suggestionHeader {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -52,37 +52,35 @@
|
||||
flex: 1;
|
||||
min-width: 7.5rem;
|
||||
|
||||
:global {
|
||||
.cm-editor {
|
||||
:global(.cm-editor) {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.cm-focused {
|
||||
:global(.cm-focused) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cm-content {
|
||||
:global(.cm-content) {
|
||||
padding: 0;
|
||||
font-family: var(--mb-default-monospace-font-family);
|
||||
font-size: 0.875rem;
|
||||
color: var(--mb-color-text-primary);
|
||||
}
|
||||
|
||||
.cm-line {
|
||||
:global(.cm-line) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cm-cursor {
|
||||
:global(.cm-cursor) {
|
||||
border-left-width: 1.6px;
|
||||
border-left-color: var(--mb-color-text-secondary);
|
||||
}
|
||||
|
||||
.cm-placeholder {
|
||||
:global(.cm-placeholder) {
|
||||
color: var(--mb-color-text-disabled);
|
||||
}
|
||||
|
||||
.cm-scroller {
|
||||
:global(.cm-scroller) {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
color: var(--mb-color-text-primary);
|
||||
background-color: var(--mb-color-background_page-secondary);
|
||||
|
||||
:global {
|
||||
/* merge view styles */
|
||||
.cm-collapsedLines {
|
||||
:global(.cm-collapsedLines) {
|
||||
background: var(--mb-color-background_page-secondary) !important;
|
||||
color: var(--mb-color-text-disabled);
|
||||
|
||||
@@ -26,34 +25,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
.cm-merge-b .cm-changedLineGutter {
|
||||
:global(.cm-merge-b .cm-changedLineGutter) {
|
||||
background: var(--change);
|
||||
}
|
||||
|
||||
.cm-deletedLineGutter {
|
||||
:global(.cm-deletedLineGutter) {
|
||||
background: var(--remove);
|
||||
}
|
||||
|
||||
.cm-deletedChunk {
|
||||
:global(.cm-deletedChunk) {
|
||||
background: var(--remove-light);
|
||||
}
|
||||
|
||||
.cm-deletedText {
|
||||
:global(.cm-deletedText) {
|
||||
background: var(--remove-mid);
|
||||
}
|
||||
|
||||
.cm-merge-b {
|
||||
.cm-changedText {
|
||||
:global(.cm-merge-b) {
|
||||
:global(.cm-changedText) {
|
||||
background: linear-gradient(var(--change), var(--change)) bottom / 100%
|
||||
2px no-repeat;
|
||||
}
|
||||
|
||||
.cm-changedLine {
|
||||
:global(.cm-changedLine) {
|
||||
background: var(--change-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: var(--mb-color-core-brand);
|
||||
|
||||
@@ -32,25 +32,21 @@
|
||||
color: var(--mb-color-text-primary);
|
||||
margin-right: calc(28px + var(--mantine-spacing-sm));
|
||||
|
||||
:global {
|
||||
.cm-gutters {
|
||||
:global(.cm-gutters) {
|
||||
border-top-left-radius: var(--mantine-radius-xs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltips {
|
||||
:global {
|
||||
.cm-tooltip {
|
||||
:global(.cm-tooltip) {
|
||||
border: none !important;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.cm-tooltip-autocomplete {
|
||||
:global(.cm-tooltip-autocomplete) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shortcuts {
|
||||
position: absolute;
|
||||
|
||||
@@ -518,7 +518,11 @@
|
||||
"cloud:dev": "bun install && clojure -A:dev:drivers:drivers-dev:ee:ee-dev:cljs -P && bun run concurrently -n 'FE,BE' -c 'blue,green' 'bun run build-hot' 'clojure -M:dev:socket:dev-start:drivers:drivers-dev:ee:ee-dev'"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
"chrome >= 120",
|
||||
"edge >= 120",
|
||||
"firefox >= 121",
|
||||
"safari >= 18.2",
|
||||
"ios_saf >= 18.2"
|
||||
],
|
||||
"packageManager": "bun@1.3.14"
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ module.exports = {
|
||||
},
|
||||
sourceMaps: false,
|
||||
minify: false,
|
||||
env: { targets: ["defaults"] },
|
||||
env: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -95,9 +95,7 @@ const SWC_LOADER = {
|
||||
|
||||
sourceMaps: true,
|
||||
minify: false, // produces same bundle size, but cuts 1s locally
|
||||
env: {
|
||||
targets: ["defaults"],
|
||||
},
|
||||
env: {},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user