@sanity/themer
0.8.10.9.0
dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js−
dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.jsDeleted−422
Index: package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js
===================================================================
--- package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js
+++ package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js
@@ -1,422 +0,0 @@
-import { a as DEFAULT_BACKGROUND, c as resolveThemeOptions, d as hslToHex, f as relativeLuminance, i as DEFAULT_ACCENT, o as SCHEMES, s as deriveTextColor, t as presets, u as hexToHsl } from "./presets-CqBgS3A-.js";
-import { createContext, useContext } from "react";
-/** @internal */
-const ThemerContext = createContext(null);
-/** @internal */
-function useThemer() {
- let context = useContext(ThemerContext);
- if (!context) throw Error("useThemer must be used within the `themerTool` plugin");
- return context;
-}
-/** @internal */
-const IMAGE_PALETTE_KEYS = [
- "vibrant",
- "lightVibrant",
- "darkVibrant",
- "muted",
- "lightMuted",
- "darkMuted",
- "dominant"
-], IMAGE_PALETTE_VARIANTS = [
- "muted",
- "vibrant",
- "lightMuted",
- "lightVibrant",
- "darkMuted",
- "darkVibrant"
-], IMAGE_PALETTE_TITLES = {
- dominant: "Dominant",
- vibrant: "Vibrant",
- lightVibrant: "Light vibrant",
- darkVibrant: "Dark vibrant",
- muted: "Muted",
- lightMuted: "Light muted",
- darkMuted: "Dark muted"
-}, TARGETS = [
- ["vibrant", {
- lightness: [
- .5,
- .3,
- .7
- ],
- saturation: [
- 1,
- .35,
- 1
- ]
- }],
- ["lightVibrant", {
- lightness: [
- .74,
- .55,
- 1
- ],
- saturation: [
- 1,
- .35,
- 1
- ]
- }],
- ["darkVibrant", {
- lightness: [
- .26,
- 0,
- .45
- ],
- saturation: [
- 1,
- .35,
- 1
- ]
- }],
- ["muted", {
- lightness: [
- .5,
- .3,
- .7
- ],
- saturation: [
- .3,
- 0,
- .4
- ]
- }],
- ["lightMuted", {
- lightness: [
- .74,
- .55,
- 1
- ],
- saturation: [
- .3,
- 0,
- .4
- ]
- }],
- ["darkMuted", {
- lightness: [
- .26,
- 0,
- .45
- ],
- saturation: [
- .3,
- 0,
- .4
- ]
- }]
-];
-/**
-* Extracts the color palette of an image from its pixels, the way the Vibrant
-* algorithm does: the colors are quantized into a coarse histogram, and each
-* swatch claims the color that comes closest to its target lightness and
-* saturation — weighted by how much of the image it covers — that no other
-* swatch has claimed yet. The dominant swatch is simply the most common
-* color. Runs anywhere pixels come from, so it can run on device.
-*
-* @internal
-*/
-function extractImagePalette(pixels) {
- let candidates = quantize(pixels), palette = {
- dominant: null,
- vibrant: null,
- lightVibrant: null,
- darkVibrant: null,
- muted: null,
- lightMuted: null,
- darkMuted: null
- };
- if (candidates.length === 0) return palette;
- let maximumPopulation = Math.max(...candidates.map((candidate) => candidate.population)), claimed = /* @__PURE__ */ new Set();
- for (let [key, target] of TARGETS) {
- let best = null, bestScore = -Infinity;
- for (let candidate of candidates) {
- if (claimed.has(candidate.hex) || !matchesTarget(candidate, target)) continue;
- let score = scoreCandidate(candidate, target, maximumPopulation);
- score > bestScore && (best = candidate, bestScore = score);
- }
- best && (palette[key] = best.hex, claimed.add(best.hex));
- }
- return palette.dominant = candidates.reduce((most, candidate) => candidate.population > most.population ? candidate : most).hex, palette;
-}
-/**
-* Turns the pixels into a histogram of quantized colors, each averaged over
-* the pixels it stands for, leaving out transparent pixels and the near-black
-* and near-white ones that are backdrop rather than color.
-*/
-function quantize(pixels) {
- let { data } = pixels, buckets = /* @__PURE__ */ new Map(), length = Math.min(data.length, pixels.width * pixels.height * 4);
- for (let offset = 0; offset + 3 < length; offset += 4) {
- let r = data[offset], g = data[offset + 1], b = data[offset + 2];
- if (data[offset + 3] < 125) continue;
- let lightness = (Math.max(r, g, b) + Math.min(r, g, b)) / 510;
- if (lightness < .05 || lightness > .95) continue;
- let key = r >> 3 << 10 | g >> 3 << 5 | b >> 3, bucket = buckets.get(key);
- bucket ? (bucket.count++, bucket.r += r, bucket.g += g, bucket.b += b) : buckets.set(key, {
- count: 1,
- r,
- g,
- b
- });
- }
- let candidates = [];
- for (let bucket of buckets.values()) {
- let r = Math.round(bucket.r / bucket.count), g = Math.round(bucket.g / bucket.count), b = Math.round(bucket.b / bucket.count), { saturation, lightness } = saturationAndLightness(r, g, b);
- candidates.push({
- hex: rgbToHex(r, g, b),
- population: bucket.count,
- saturation,
- lightness
- });
- }
- return candidates;
-}
-function matchesTarget(candidate, target) {
- return candidate.lightness >= target.lightness[1] && candidate.lightness <= target.lightness[2] && candidate.saturation >= target.saturation[1] && candidate.saturation <= target.saturation[2];
-}
-function scoreCandidate(candidate, target, maximumPopulation) {
- return 3 * (1 - Math.abs(candidate.saturation - target.saturation[0])) + 6.5 * (1 - Math.abs(candidate.lightness - target.lightness[0])) + .5 * (candidate.population / maximumPopulation);
-}
-function saturationAndLightness(r, g, b) {
- let max = Math.max(r, g, b) / 255, min = Math.min(r, g, b) / 255, lightness = (max + min) / 2, delta = max - min;
- return {
- saturation: delta === 0 ? 0 : lightness > .5 ? delta / (2 - max - min) : delta / (max + min),
- lightness
- };
-}
-function rgbToHex(r, g, b) {
- return `#${[
- r,
- g,
- b
- ].map((channel) => channel.toString(16).padStart(2, "0")).join("")}`;
-}
-/** Reads `#rgb` and `#rrggbb` alike — stored palettes may hold either */
-function hexToRgb(hex) {
- let expanded = hex.length === 4 ? `${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex.slice(1);
- return [
- parseInt(expanded.slice(0, 2), 16),
- parseInt(expanded.slice(2, 4), 16),
- parseInt(expanded.slice(4, 6), 16)
- ];
-}
-/** Mixes `amount` of `color` into `base` */
-function tint(base, color, amount) {
- let [r1, g1, b1] = hexToRgb(base), [r2, g2, b2] = hexToRgb(color);
- return rgbToHex(Math.round(r1 + (r2 - r1) * amount), Math.round(g1 + (g2 - g1) * amount), Math.round(b1 + (b2 - b1) * amount));
-}
-/** How much of the palette tints each scheme's stock background */
-const BACKGROUND_TINT = {
- light: .08,
- dark: .3
-}, BUTTON_LABEL = {
- light: "#ffffff",
- dark: "#000000"
-}, ACCENT_LIGHTNESS_STEP = .01;
-function contrastRatio(a, b) {
- let [lighter, darker] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
- return (lighter + .05) / (darker + .05);
-}
-/**
-* Makes an accent readable as a button in the given scheme: a light scheme
-* accent is darkened until white text on it reaches AA contrast, a dark
-* scheme accent lightened until black text does — as far as the accent's
-* hue and saturation allow. Accents that already pass come back untouched.
-*
-* @internal
-*/
-function readableAccent(hex, scheme) {
- let label = BUTTON_LABEL[scheme], { h, s } = hexToHsl(hex), { l } = hexToHsl(hex), current = hex;
- for (; contrastRatio(current, label) < 4.5;) {
- let next = scheme === "light" ? l - ACCENT_LIGHTNESS_STEP : l + ACCENT_LIGHTNESS_STEP;
- if (next < 0 || next > 1) break;
- l = next, current = hslToHex({
- h,
- s,
- l
- });
- }
- return current;
-}
-/** The accent a variant gives a scheme, made readable on a button */
-function variantAccent(palette, variant, scheme) {
- let swatch = (variant ? palette[variant] : null) ?? palette.vibrant ?? (scheme === "light" ? palette.darkVibrant : palette.lightVibrant) ?? palette.dominant;
- return swatch === null ? null : readableAccent(swatch, scheme);
-}
-/**
-* Derives theme options from an image palette: the accent of both schemes is
-* the swatch of the chosen variant — or, without one, the vibrant swatch,
-* each scheme falling back to the vibrant swatch of its own end of the scale —
-* adjusted until it is readable as a button. The muted swatch becomes the text color, and the light and dark muted
-* swatches tint the stock backgrounds of their scheme — enough to carry the
-* image's tone without giving up a usable canvas. Whatever the palette lacks
-* stays at the theme defaults.
-*
-* @internal
-*/
-function optionsFromImagePalette(palette, variant) {
- let options = {}, light = schemeFromPalette(variantAccent(palette, variant ?? null, "light"), palette.muted ?? palette.darkMuted, palette.lightMuted ?? palette.muted ?? palette.lightVibrant, "light"), dark = schemeFromPalette(variantAccent(palette, variant ?? null, "dark"), palette.muted ?? palette.lightMuted, palette.darkMuted ?? palette.muted ?? palette.darkVibrant, "dark");
- return light && (options.light = light), dark && (options.dark = dark), options;
-}
-function schemeFromPalette(accent, text, backgroundTint, scheme) {
- let options = {};
- return accent && (options.accent = accent), text && (options.text = text), backgroundTint && (options.background = tint(DEFAULT_BACKGROUND[scheme], backgroundTint, BACKGROUND_TINT[scheme])), Object.keys(options).length > 0 ? options : null;
-}
-/**
-* Applies an image palette to existing theme options: the colors the palette
-* provides replace the current ones scheme by scheme, and whatever it does
-* not touch — like the contrast — stays as it is.
-*
-* @internal
-*/
-function applyImagePalette(options, palette, variant) {
- let derived = optionsFromImagePalette(palette, variant), next = { ...options };
- for (let scheme of SCHEMES) derived[scheme] && (next[scheme] = {
- ...options[scheme],
- ...derived[scheme]
- });
- return next;
-}
-/**
-* The variant a theme is built around: the one whose swatch is the theme's
-* accent, or `null` when the accent comes from somewhere else.
-*
-* @internal
-*/
-function currentImageVariant(options, palette) {
- let accent = options.light?.accent;
- return accent ? IMAGE_PALETTE_VARIANTS.find((variant) => palette[variant] !== null && variantAccent(palette, variant, "light") === accent) ?? null : null;
-}
-/**
-* How much a swatch has going for it as an accent: saturation first, then
-* closeness to mid lightness — the range where an accent reads best.
-*/
-function interest(hex) {
- let { s, l } = hexToHsl(hex);
- return .1 + .55 * s + .35 * (1 - Math.abs(l - .5) * 2);
-}
-/**
-* Picks a variant for the "I'm feeling lucky" button: a random one, weighted
-* by how interesting its swatch is as an accent, and never the one the theme
-* already uses while there are others to pick from.
-*
-* @internal
-*/
-function pickLuckyVariant(palette, options = {}) {
- let { exclude = null, random = Math.random } = options, candidates = IMAGE_PALETTE_VARIANTS.filter((variant) => palette[variant] !== null);
- if (candidates.length > 1 && (candidates = candidates.filter((variant) => variant !== exclude)), candidates.length === 0) return null;
- let weights = candidates.map((variant) => interest(palette[variant])), total = weights.reduce((sum, weight) => sum + weight, 0), pick = random() * total;
- for (let [index, variant] of candidates.entries()) if (pick -= weights[index], pick < 0) return variant;
- return candidates.at(-1) ?? null;
-}
-/** A theme title for the image a palette came from, e.g. `sunset-beach.jpg` → `sunset beach` @internal */
-function titleFromFileName(name) {
- return name.replace(/\.[^.]+$/, "").replace(/[-_]+/g, " ").trim() || "Image theme";
-}
-/**
-* Reduces theme options to the minimal object that recreates them through
-* `buildTheme`: in each scheme the accent is dropped when it is the stock
-* one, the text color when it matches the one derived from the accent, and
-* the background and contrast when they match the defaults — and a scheme
-* with nothing left is dropped altogether. Options that boil down to the
-* stock Studio theme reduce to `null` — they need nothing from this package.
-*
-* @internal
-*/
-function minimizeOptions(options) {
- let resolved = resolveThemeOptions(options), minimized = {};
- for (let scheme of SCHEMES) {
- let values = resolved[scheme], kept = {};
- values.accent !== DEFAULT_ACCENT && (kept.accent = values.accent), values.text !== deriveTextColor(values.accent) && (kept.text = values.text), values.background !== DEFAULT_BACKGROUND[scheme] && (kept.background = values.background), values.contrast !== 85 && (kept.contrast = values.contrast), Object.keys(kept).length > 0 && (minimized[scheme] = kept);
- }
- return Object.keys(minimized).length === 0 ? null : minimized;
-}
-/**
-* Whether two sets of theme options generate the same theme, comparing their
-* resolved forms so that derived and explicit values (and hex casing) don't
-* matter.
-*
-* @internal
-*/
-function sameOptions(a, b) {
- let left = resolveThemeOptions(a), right = resolveThemeOptions(b);
- return SCHEMES.every((scheme) => sameScheme(left[scheme], right[scheme]));
-}
-function sameScheme(a, b) {
- return a.accent === b.accent && a.text === b.text && a.background === b.background && a.contrast === b.contrast;
-}
-/** The slug of the theme the Studio config was generated from @internal */
-const CONFIG_SLUG = "config", UNTITLED_THEME = "Untitled theme", initialThemerState = {
- active: null,
- custom: [],
- removed: [],
- order: []
-};
-/**
-* Resolves the list of themes: the configured theme first, then the presets
-* (minus the ones that would only repeat the configured theme), then the
-* user's own themes — rearranged into the order the user dragged them into,
-* with themes that order does not know about kept in that default order after
-* the ones it does. Removed themes are set aside so they can be restored, and
-* the active theme falls back to the configured one when its slug no longer
-* resolves.
-*
-* @internal
-*/
-function resolveThemes(state, baseOptions) {
- let config = {
- slug: CONFIG_SLUG,
- title: "Studio config",
- options: baseOptions,
- source: "config"
- }, all = [config];
- for (let preset of presets) sameOptions(preset.options, baseOptions) || all.push({
- slug: preset.slug,
- title: preset.title,
- options: preset.options,
- source: "preset"
- });
- for (let theme of state.custom) all.push({
- slug: theme.slug,
- title: theme.title,
- options: theme.options,
- source: "custom",
- ...theme.palette ? { palette: theme.palette } : {}
- });
- let position = new Map(state.order.map((slug, index) => [slug, index])), rank = (theme) => position.get(theme.slug) ?? state.order.length;
- all.sort((a, b) => rank(a) - rank(b));
- let removedSlugs = new Set(state.removed), themes = all.filter((theme) => !removedSlugs.has(theme.slug));
- return {
- themes,
- removed: all.filter((theme) => removedSlugs.has(theme.slug)),
- active: themes.find((theme) => theme.slug === state.active) ?? config
- };
-}
-/**
-* Creates a custom theme with a slug that cannot collide with the presets or
-* the configured theme.
-*
-* @internal
-*/
-function createCustomTheme(title, options, palette) {
- return {
- slug: `custom-${randomId()}`,
- title,
- options,
- ...palette ? { palette } : {}
- };
-}
-/** The title of a duplicated theme @internal */
-function duplicateTitle(title) {
- return `${displayTitle(title)} copy`;
-}
-/** The title to show for a theme, falling back when the user cleared it @internal */
-function displayTitle(title) {
- return title.trim() || "Untitled theme";
-}
-function randomId() {
- return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
-}
-export { titleFromFileName as _, duplicateTitle as a, minimizeOptions as c, IMAGE_PALETTE_VARIANTS as d, applyImagePalette as f, pickLuckyVariant as g, optionsFromImagePalette as h, displayTitle as i, IMAGE_PALETTE_KEYS as l, extractImagePalette as m, UNTITLED_THEME as n, initialThemerState as o, currentImageVariant as p, createCustomTheme as r, resolveThemes as s, CONFIG_SLUG as t, IMAGE_PALETTE_TITLES as u, ThemerContext as v, useThemer as y };
-
-//# sourceMappingURL=ResizableSidebar.css.ts.vanilla-M9EuPu-q.js.map
\ No newline at end of file