--
: /documentation/breaking-changes/css-function-mixin/
- Mixed Declarations: /documentation/breaking-changes/mixed-decls/
- meta.feature-exists
: /documentation/breaking-changes/feature-exists/
+ - Color Functions: /documentation/breaking-changes/color-functions/
+ - Legacy JS API: /documentation/breaking-changes/legacy-js-api/
- Command Line: /documentation/cli/
:children:
- Dart Sass: /documentation/cli/dart-sass/
diff --git a/source/_includes/silencing_deprecations.liquid b/source/_includes/silencing_deprecations.liquid
index 2e4d1c1c0..ea34d0e7c 100644
--- a/source/_includes/silencing_deprecations.liquid
+++ b/source/_includes/silencing_deprecations.liquid
@@ -55,9 +55,3 @@ option] in the JavaScript API.
[`--silence-deprecation` flag]: /documentation/cli/dart-sass/#silence-deprecation
[`silenceDeprecations` option]: /documentation/js-api/interfaces/Options/#silenceDeprecations
-
-{% headsUp %}
- This option is only available in the [modern JS API].
-
- [modern JS API]: /documentation/js-api/#md:usage
-{% endheadsUp %}
diff --git a/source/assets/img/blog/042-blue-yellow.jpg b/source/assets/img/blog/042-blue-yellow.jpg
new file mode 100644
index 000000000..9b1096322
Binary files /dev/null and b/source/assets/img/blog/042-blue-yellow.jpg differ
diff --git a/source/assets/img/blog/042-p3-hsl.png b/source/assets/img/blog/042-p3-hsl.png
new file mode 100644
index 000000000..dd4b01f14
Binary files /dev/null and b/source/assets/img/blog/042-p3-hsl.png differ
diff --git a/source/assets/img/blog/042-p3-oklch.png b/source/assets/img/blog/042-p3-oklch.png
new file mode 100644
index 000000000..cd78fe6e7
Binary files /dev/null and b/source/assets/img/blog/042-p3-oklch.png differ
diff --git a/source/assets/img/blog/042-p3-srgb.png b/source/assets/img/blog/042-p3-srgb.png
new file mode 100644
index 000000000..450b90889
Binary files /dev/null and b/source/assets/img/blog/042-p3-srgb.png differ
diff --git a/source/assets/img/blog/042-srgb-hsl.png b/source/assets/img/blog/042-srgb-hsl.png
new file mode 100644
index 000000000..54caf1460
Binary files /dev/null and b/source/assets/img/blog/042-srgb-hsl.png differ
diff --git a/source/assets/img/blog/042-srgb-hwb.png b/source/assets/img/blog/042-srgb-hwb.png
new file mode 100644
index 000000000..e1600051a
Binary files /dev/null and b/source/assets/img/blog/042-srgb-hwb.png differ
diff --git a/source/assets/img/blog/042-srgb.png b/source/assets/img/blog/042-srgb.png
new file mode 100644
index 000000000..72d54d8e9
Binary files /dev/null and b/source/assets/img/blog/042-srgb.png differ
diff --git a/source/assets/js/playground.ts b/source/assets/js/playground.ts
index 9b8a62875..c215bff9a 100644
--- a/source/assets/js/playground.ts
+++ b/source/assets/js/playground.ts
@@ -14,6 +14,7 @@ import {
} from './playground/editor-setup.js';
import {
ParseResult,
+ PlaygroundSelection,
PlaygroundState,
customLoader,
deserializeState,
@@ -111,9 +112,7 @@ function setupPlayground(): void {
* Returns a playground state selection for the current single non-empty
* selection, or `null` otherwise.
*/
- function editorSelectionToStateSelection():
- | PlaygroundState['selection']
- | null {
+ function editorSelectionToStateSelection(): PlaygroundSelection {
const sel = editor.state.selection;
if (sel.ranges.length !== 1) return null;
@@ -130,7 +129,7 @@ function setupPlayground(): void {
];
}
- /** Updates the editor's selection based on `playgroundState.selection`. */
+ /** Updates the {@link editor}'s selection based on `{@link playgroundState.selection}`. */
function updateSelection(): void {
if (playgroundState.selection === null) {
const sel = editor.state.selection;
@@ -162,6 +161,13 @@ function setupPlayground(): void {
}
}
+ /** Highlights {@link selection} and focuses on the {@link editor}. */
+ function goToSelection(selection: PlaygroundSelection): void {
+ playgroundState.selection = selection;
+ updateSelection();
+ editor.focus();
+ }
+
// Apply initial state to dom
function applyInitialState(): void {
updateButtonState();
@@ -301,8 +307,22 @@ function setupPlayground(): void {
'.sl-c-playground__console'
) as HTMLDivElement;
console.innerHTML = playgroundState.debugOutput
- .map(displayForConsoleLog)
+ .map(item => displayForConsoleLog(item, playgroundState))
.join('\n');
+ console.querySelectorAll('a.console-location').forEach(link => {
+ (link as HTMLAnchorElement).addEventListener('click', event => {
+ if (!(event.metaKey || event.altKey || event.shiftKey)) {
+ event.preventDefault();
+ }
+ const range = (event.currentTarget as HTMLAnchorElement).dataset.range
+ ?.split(',')
+ .map(n => parseInt(n));
+ if (range && range.length === 4) {
+ const [fromL, fromC, toL, toC] = range;
+ goToSelection([fromL, fromC, toL, toC]);
+ }
+ });
+ });
}
function updateDiagnostics(): void {
diff --git a/source/assets/js/playground/autocomplete.ts b/source/assets/js/playground/autocomplete.ts
new file mode 100644
index 000000000..1f387bb06
--- /dev/null
+++ b/source/assets/js/playground/autocomplete.ts
@@ -0,0 +1,249 @@
+import {
+ CompletionContext,
+ CompletionResult,
+ CompletionSource,
+} from '@codemirror/autocomplete';
+import {sassCompletionSource} from '@codemirror/lang-sass';
+import {syntaxTree} from '@codemirror/language';
+import {EditorState} from '@codemirror/state';
+import moduleMetadata from './module-metadata';
+
+// The validFor identifier, from @codemirror/lang-css. After an initial set of
+// possible completions are returned from a completion soruce, the matched set
+// narrows as the user types as long as it matches this identifier. Once it no
+// longer matches, the completion sources are checked again.
+// https://codemirror.net/docs/ref/#autocomplete.CompletionResult.validFor
+const identifier = /^(\w[\w-]*|-\w[\w-]*|)$/;
+
+// Sass-specific at rules only. CSS at rules should be added to `@codemirror/lang-css`.
+const atRuleKeywords = [
+ 'use',
+ 'forward',
+ 'import',
+ 'mixin',
+ 'include',
+ 'function',
+ 'extend',
+ 'error',
+ 'warn',
+ 'debug',
+ 'at-root',
+ 'if',
+ 'else',
+ 'each',
+ 'for',
+ 'while',
+];
+
+// CompletionResult options for Sass at rules, for example `@use`.
+const atRuleOptions = Object.freeze(
+ atRuleKeywords.map(keyword => ({
+ label: `@${keyword} `,
+ type: 'keyword',
+ validFor: identifier,
+ }))
+);
+
+// Completions for Sass at rules
+function atRuleCompletion(context: CompletionContext): CompletionResult | null {
+ const atRule = context.matchBefore(/@\w*/);
+ if (!atRule) return null;
+ if (atRule.from === atRule.to && !context.explicit) return null;
+ return {
+ from: atRule.from,
+ to: atRule.to,
+ options: atRuleOptions,
+ validFor: identifier,
+ };
+}
+
+// A list of all the Sass built in modules.
+const moduleNames = moduleMetadata.map(mod => mod.name);
+type ModuleName = (typeof moduleNames)[number];
+
+// Matches an identifier namespaced within any of the built in Sass modules.
+const moduleNameRegExp = new RegExp(`(${moduleNames.join('|')}).\\$?\\w*`);
+
+// Matches the StringLiteral `"sass:modName"`, capturing `modName`.
+const moduleUseRegex = new RegExp(/['"]sass:(?Space | +Syntax | +Channels [min, max] | +
---|---|---|
rgb * |
+
+ rgb(102 51 153) + #663399 + rebeccapurple
+ |
+ + red [0, 255]; + green [0, 255]; + blue [0, 255] + | +
hsl * |
+ hsl(270 50% 40%) |
+ + hue [0, 360]; + saturation [0%, 100%]; + lightness [0%, 100%] + | +
hwb * |
+ hwb(270 20% 40%) |
+ + hue [0, 360]; + whiteness [0%, 100%]; + blackness [0%, 100%] + | +
srgb |
+ color(srgb 0.4 0.2 0.6) |
+ + red [0, 1]; + green [0, 1]; + blue [0, 1] + | +
srgb-linear |
+ color(srgb-linear 0.133 0.033 0.319) |
+ + red [0, 1]; + green [0, 1]; + blue [0, 1] + | +
display-p3 |
+ color(display-p3 0.374 0.21 0.579) |
+ + red [0, 1]; + green [0, 1]; + blue [0, 1] + | +
a98-rgb |
+ color(a98-rgb 0.358 0.212 0.584) |
+ + red [0, 1]; + green [0, 1]; + blue [0, 1] + | +
prophoto-rgb |
+ color(prophoto-rgb 0.316 0.191 0.495) |
+ + red [0, 1]; + green [0, 1]; + blue [0, 1] + | +
rec2020 |
+ color(rec2020 0.305 0.168 0.531) |
+ + red [0, 1]; + green [0, 1]; + blue [0, 1] + | +
xyz , xyz-d65 |
+
+ color(xyz 0.124 0.075 0.309) + color(xyz-d65 0.124 0.075 0.309)
+ |
+ + x [0, 1]; + y [0, 1]; + z [0, 1] + | +
xyz-d50 |
+ color(xyz-d50 0.116 0.073 0.233) |
+ + x [0, 1]; + y [0, 1]; + z [0, 1] + | +
lab |
+ lab(32.4% 38.4 -47.7) |
+ + lightness [0%, 100%]; + a [-125, 125]; + b [-125, 125] + | +
lch |
+ lch(32.4% 61.2 308.9deg) |
+ + lightness [0%, 100%]; + chroma [0, 150]; + hue [0deg, 360deg] + | +
oklab |
+ oklab(44% 0.088 -0.134) |
+ + lightness [0%, 100%]; + a [-0.4, 0.4]; + b [-0.4, 0.4] + | +
oklch |
+ oklch(44% 0.16 303.4deg) |
+ + lightness [0%, 100%]; + chroma [0, 0.4]; + hue [0deg, 360deg] + | +