@omerdlw/base-framework 2.0.1 → 3.0.0
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/README.md +4 -1
- package/dist/{chunk-XASQT4CQ.js → chunk-66EYJBIP.js} +47 -27
- package/dist/chunk-66EYJBIP.js.map +1 -0
- package/dist/{chunk-SKBITB5X.js → chunk-CYU6SGAL.js} +3 -3
- package/dist/{chunk-SKBITB5X.js.map → chunk-CYU6SGAL.js.map} +1 -1
- package/dist/{chunk-6SG7V77J.js → chunk-HHWRTQKQ.js} +100 -67
- package/dist/chunk-HHWRTQKQ.js.map +1 -0
- package/dist/chunk-HLL5EHXC.js +485 -0
- package/dist/chunk-HLL5EHXC.js.map +1 -0
- package/dist/{chunk-A5RE3F6O.js → chunk-JIXBFFRD.js} +193 -357
- package/dist/chunk-JIXBFFRD.js.map +1 -0
- package/dist/{chunk-6ZJVLUBE.js → chunk-M57SNWXK.js} +8 -6
- package/dist/chunk-M57SNWXK.js.map +1 -0
- package/dist/chunk-RIOKLMYM.js +145 -0
- package/dist/chunk-RIOKLMYM.js.map +1 -0
- package/dist/{chunk-QXR55VVS.js → chunk-TG6NMHXI.js} +241 -162
- package/dist/chunk-TG6NMHXI.js.map +1 -0
- package/dist/index.js +7 -5
- package/dist/modules/ambient/analyze.d.ts +18 -3
- package/dist/modules/ambient/analyze.d.ts.map +1 -1
- package/dist/modules/ambient/dom.d.ts +14 -1
- package/dist/modules/ambient/dom.d.ts.map +1 -1
- package/dist/modules/ambient/hooks.d.ts.map +1 -1
- package/dist/modules/ambient/index.d.ts +2 -2
- package/dist/modules/ambient/index.d.ts.map +1 -1
- package/dist/modules/ambient/index.js +1 -1
- package/dist/modules/ambient/server/index.d.ts +1 -1
- package/dist/modules/ambient/server/index.d.ts.map +1 -1
- package/dist/modules/ambient/server/index.js +2 -2
- package/dist/modules/ambient/server/index.js.map +1 -1
- package/dist/modules/ambient/settings.d.ts +1 -0
- package/dist/modules/ambient/settings.d.ts.map +1 -1
- package/dist/modules/ambient/types.d.ts +13 -0
- package/dist/modules/ambient/types.d.ts.map +1 -1
- package/dist/modules/ambient/worker/index.js +1 -1
- package/dist/modules/context-menu/index.js +4 -3
- package/dist/modules/dock/cards.d.ts.map +1 -1
- package/dist/modules/dock/constants.d.ts +1 -20
- package/dist/modules/dock/constants.d.ts.map +1 -1
- package/dist/modules/dock/index.js +3 -2
- package/dist/modules/dock/routing/guards.d.ts +1 -1
- package/dist/modules/dock/routing/navigation.d.ts +7 -4
- package/dist/modules/dock/routing/navigation.d.ts.map +1 -1
- package/dist/modules/dock/runtime/display.d.ts +31 -2
- package/dist/modules/dock/runtime/display.d.ts.map +1 -1
- package/dist/modules/dock/runtime/dock.d.ts +2 -2
- package/dist/modules/dock/runtime/dock.d.ts.map +1 -1
- package/dist/modules/dock/types.d.ts +5 -27
- package/dist/modules/dock/types.d.ts.map +1 -1
- package/dist/modules/index.d.ts +3 -2
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +7 -5
- package/dist/modules/loading/context.d.ts.map +1 -1
- package/dist/modules/loading/index.js +1 -1
- package/dist/modules/navigation/constants.d.ts +37 -0
- package/dist/modules/navigation/constants.d.ts.map +1 -0
- package/dist/modules/navigation/context.d.ts +10 -0
- package/dist/modules/navigation/context.d.ts.map +1 -0
- package/dist/modules/navigation/hooks.d.ts +29 -0
- package/dist/modules/navigation/hooks.d.ts.map +1 -0
- package/dist/modules/navigation/index.d.ts +10 -0
- package/dist/modules/navigation/index.d.ts.map +1 -0
- package/dist/modules/navigation/index.js +81 -0
- package/dist/modules/navigation/index.js.map +1 -0
- package/dist/modules/navigation/listeners.d.ts +15 -0
- package/dist/modules/navigation/listeners.d.ts.map +1 -0
- package/dist/modules/navigation/module.d.ts +25 -0
- package/dist/modules/navigation/module.d.ts.map +1 -0
- package/dist/modules/navigation/navigator.d.ts +8 -0
- package/dist/modules/navigation/navigator.d.ts.map +1 -0
- package/dist/modules/navigation/settings.d.ts +10 -0
- package/dist/modules/navigation/settings.d.ts.map +1 -0
- package/dist/modules/navigation/state.d.ts +20 -0
- package/dist/modules/navigation/state.d.ts.map +1 -0
- package/dist/modules/navigation/types.d.ts +168 -0
- package/dist/modules/navigation/types.d.ts.map +1 -0
- package/dist/modules/navigation/utils.d.ts +11 -0
- package/dist/modules/navigation/utils.d.ts.map +1 -0
- package/docs/getting-started.md +2 -0
- package/docs/modules/README.md +5 -1
- package/docs/modules/ambient.md +9 -6
- package/docs/modules/dock.md +12 -10
- package/docs/modules/loading.md +2 -2
- package/docs/modules/navigation.md +216 -0
- package/docs/proposals/navigation.md +209 -0
- package/package.json +6 -1
- package/templates/AGENTS.md +2 -0
- package/dist/chunk-6SG7V77J.js.map +0 -1
- package/dist/chunk-6ZJVLUBE.js.map +0 -1
- package/dist/chunk-A5RE3F6O.js.map +0 -1
- package/dist/chunk-QXR55VVS.js.map +0 -1
- package/dist/chunk-XASQT4CQ.js.map +0 -1
- package/dist/modules/dock/routing/transactions.d.ts +0 -21
- package/dist/modules/dock/routing/transactions.d.ts.map +0 -1
|
@@ -38,6 +38,94 @@ function AmbientProvider({
|
|
|
38
38
|
// src/modules/ambient/constants.ts
|
|
39
39
|
var ambientTheme = defineThemeSpec("ambient");
|
|
40
40
|
|
|
41
|
+
// src/modules/ambient/settings.ts
|
|
42
|
+
var AMBIENT_TONES = Object.freeze([
|
|
43
|
+
10,
|
|
44
|
+
15,
|
|
45
|
+
20,
|
|
46
|
+
30,
|
|
47
|
+
40,
|
|
48
|
+
50,
|
|
49
|
+
60,
|
|
50
|
+
70,
|
|
51
|
+
80,
|
|
52
|
+
90,
|
|
53
|
+
95
|
|
54
|
+
]);
|
|
55
|
+
var AMBIENT_ROLES = Object.freeze([
|
|
56
|
+
"dominant",
|
|
57
|
+
"vibrant",
|
|
58
|
+
"muted",
|
|
59
|
+
"accent"
|
|
60
|
+
]);
|
|
61
|
+
var AMBIENT_REGIONS = Object.freeze([
|
|
62
|
+
"top",
|
|
63
|
+
"bottom",
|
|
64
|
+
"left",
|
|
65
|
+
"right",
|
|
66
|
+
"center"
|
|
67
|
+
]);
|
|
68
|
+
var DEFAULT_ANALYSIS = Object.freeze({
|
|
69
|
+
centerWeight: 0.5,
|
|
70
|
+
clusters: 7,
|
|
71
|
+
letterbox: true,
|
|
72
|
+
minContrast: 4.5,
|
|
73
|
+
minHueDistance: 40,
|
|
74
|
+
sampleSize: 128,
|
|
75
|
+
shadowLightness: 0.16
|
|
76
|
+
});
|
|
77
|
+
var DEFAULT_CSS_VAR_NAMES = Object.freeze({
|
|
78
|
+
on: "--ambient-on-{role}",
|
|
79
|
+
region: "--ambient-{region}",
|
|
80
|
+
role: "--ambient-{role}",
|
|
81
|
+
shadow: "--ambient-shadow",
|
|
82
|
+
tone: "--ambient-{role}-{tone}"
|
|
83
|
+
});
|
|
84
|
+
var DEFAULT_PROXY = "/api/ambient/proxy?url=";
|
|
85
|
+
var DEFAULT_LINGER_MS = 3e3;
|
|
86
|
+
var createDefaults = () => ({
|
|
87
|
+
analysis: { ...DEFAULT_ANALYSIS },
|
|
88
|
+
cacheLimit: 100,
|
|
89
|
+
cssVars: { ...DEFAULT_CSS_VAR_NAMES, tones: AMBIENT_TONES },
|
|
90
|
+
linger: DEFAULT_LINGER_MS,
|
|
91
|
+
proxy: DEFAULT_PROXY,
|
|
92
|
+
strategy: "auto",
|
|
93
|
+
worker: null
|
|
94
|
+
});
|
|
95
|
+
var SETTINGS_KEY = /* @__PURE__ */ Symbol.for("@omerdlw/base-framework/ambient/settings");
|
|
96
|
+
var scope = globalThis;
|
|
97
|
+
function getAmbientSettings() {
|
|
98
|
+
return scope[SETTINGS_KEY] ??= createDefaults();
|
|
99
|
+
}
|
|
100
|
+
function mergeAmbientSettings(base, input) {
|
|
101
|
+
return {
|
|
102
|
+
analysis: { ...base.analysis, ...input.analysis },
|
|
103
|
+
cacheLimit: input.cacheLimit ?? base.cacheLimit,
|
|
104
|
+
cssVars: { ...base.cssVars, ...input.cssVars },
|
|
105
|
+
linger: input.linger ?? base.linger,
|
|
106
|
+
proxy: input.proxy === void 0 ? base.proxy : input.proxy,
|
|
107
|
+
strategy: input.strategy ?? base.strategy,
|
|
108
|
+
worker: input.worker === void 0 ? base.worker : input.worker
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function configureAmbient(input) {
|
|
112
|
+
const previous = getAmbientSettings();
|
|
113
|
+
const next = mergeAmbientSettings(previous, input);
|
|
114
|
+
scope[SETTINGS_KEY] = next;
|
|
115
|
+
return () => {
|
|
116
|
+
if (scope[SETTINGS_KEY] === next) scope[SETTINGS_KEY] = previous;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function resolveAnalysis(overrides) {
|
|
120
|
+
return { ...getAmbientSettings().analysis, ...overrides };
|
|
121
|
+
}
|
|
122
|
+
function resolveProxyUrl(proxy, src) {
|
|
123
|
+
if (!proxy || !/^https?:\/\//i.test(src)) return null;
|
|
124
|
+
if (typeof proxy === "function") return proxy(src);
|
|
125
|
+
const encoded = encodeURIComponent(src);
|
|
126
|
+
return proxy.includes("{url}") ? proxy.replace("{url}", encoded) : `${proxy}${encoded}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
41
129
|
// src/modules/ambient/oklab.ts
|
|
42
130
|
var DEG = Math.PI / 180;
|
|
43
131
|
var LINEAR_LUT = new Float32Array(256);
|
|
@@ -132,91 +220,6 @@ function onColorFor(background, minContrast = 4.5) {
|
|
|
132
220
|
return useLight ? { c: 0, h: 0, l: 1 } : { c: 0, h: 0, l: 0 };
|
|
133
221
|
}
|
|
134
222
|
|
|
135
|
-
// src/modules/ambient/settings.ts
|
|
136
|
-
var AMBIENT_TONES = Object.freeze([
|
|
137
|
-
10,
|
|
138
|
-
15,
|
|
139
|
-
20,
|
|
140
|
-
30,
|
|
141
|
-
40,
|
|
142
|
-
50,
|
|
143
|
-
60,
|
|
144
|
-
70,
|
|
145
|
-
80,
|
|
146
|
-
90,
|
|
147
|
-
95
|
|
148
|
-
]);
|
|
149
|
-
var AMBIENT_ROLES = Object.freeze([
|
|
150
|
-
"dominant",
|
|
151
|
-
"vibrant",
|
|
152
|
-
"muted",
|
|
153
|
-
"accent"
|
|
154
|
-
]);
|
|
155
|
-
var AMBIENT_REGIONS = Object.freeze([
|
|
156
|
-
"top",
|
|
157
|
-
"bottom",
|
|
158
|
-
"left",
|
|
159
|
-
"right",
|
|
160
|
-
"center"
|
|
161
|
-
]);
|
|
162
|
-
var DEFAULT_ANALYSIS = Object.freeze({
|
|
163
|
-
centerWeight: 0.5,
|
|
164
|
-
clusters: 7,
|
|
165
|
-
letterbox: true,
|
|
166
|
-
minContrast: 4.5,
|
|
167
|
-
minHueDistance: 40,
|
|
168
|
-
sampleSize: 128,
|
|
169
|
-
shadowLightness: 0.16
|
|
170
|
-
});
|
|
171
|
-
var DEFAULT_CSS_VAR_NAMES = Object.freeze({
|
|
172
|
-
on: "--ambient-on-{role}",
|
|
173
|
-
region: "--ambient-{region}",
|
|
174
|
-
role: "--ambient-{role}",
|
|
175
|
-
shadow: "--ambient-shadow",
|
|
176
|
-
tone: "--ambient-{role}-{tone}"
|
|
177
|
-
});
|
|
178
|
-
var DEFAULT_PROXY = "/api/ambient/proxy?url=";
|
|
179
|
-
var createDefaults = () => ({
|
|
180
|
-
analysis: { ...DEFAULT_ANALYSIS },
|
|
181
|
-
cacheLimit: 100,
|
|
182
|
-
cssVars: { ...DEFAULT_CSS_VAR_NAMES, tones: AMBIENT_TONES },
|
|
183
|
-
proxy: DEFAULT_PROXY,
|
|
184
|
-
strategy: "auto",
|
|
185
|
-
worker: null
|
|
186
|
-
});
|
|
187
|
-
var SETTINGS_KEY = /* @__PURE__ */ Symbol.for("@omerdlw/base-framework/ambient/settings");
|
|
188
|
-
var scope = globalThis;
|
|
189
|
-
function getAmbientSettings() {
|
|
190
|
-
return scope[SETTINGS_KEY] ??= createDefaults();
|
|
191
|
-
}
|
|
192
|
-
function mergeAmbientSettings(base, input) {
|
|
193
|
-
return {
|
|
194
|
-
analysis: { ...base.analysis, ...input.analysis },
|
|
195
|
-
cacheLimit: input.cacheLimit ?? base.cacheLimit,
|
|
196
|
-
cssVars: { ...base.cssVars, ...input.cssVars },
|
|
197
|
-
proxy: input.proxy === void 0 ? base.proxy : input.proxy,
|
|
198
|
-
strategy: input.strategy ?? base.strategy,
|
|
199
|
-
worker: input.worker === void 0 ? base.worker : input.worker
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
function configureAmbient(input) {
|
|
203
|
-
const previous = getAmbientSettings();
|
|
204
|
-
const next = mergeAmbientSettings(previous, input);
|
|
205
|
-
scope[SETTINGS_KEY] = next;
|
|
206
|
-
return () => {
|
|
207
|
-
if (scope[SETTINGS_KEY] === next) scope[SETTINGS_KEY] = previous;
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
function resolveAnalysis(overrides) {
|
|
211
|
-
return { ...getAmbientSettings().analysis, ...overrides };
|
|
212
|
-
}
|
|
213
|
-
function resolveProxyUrl(proxy, src) {
|
|
214
|
-
if (!proxy || !/^https?:\/\//i.test(src)) return null;
|
|
215
|
-
if (typeof proxy === "function") return proxy(src);
|
|
216
|
-
const encoded = encodeURIComponent(src);
|
|
217
|
-
return proxy.includes("{url}") ? proxy.replace("{url}", encoded) : `${proxy}${encoded}`;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
223
|
// src/modules/ambient/quantize.ts
|
|
221
224
|
function kmeans(points, weights, requested, { iterations = 16, lightnessWeight = 0.45 } = {}) {
|
|
222
225
|
const n = weights.length;
|
|
@@ -290,6 +293,7 @@ function kmeans(points, weights, requested, { iterations = 16, lightnessWeight =
|
|
|
290
293
|
}
|
|
291
294
|
|
|
292
295
|
// src/modules/ambient/analyze.ts
|
|
296
|
+
var AMBIENT_ANALYSIS_VERSION = 2;
|
|
293
297
|
var MIN_CHROMA = 0.022;
|
|
294
298
|
var MIN_PRESENCE = 0.03;
|
|
295
299
|
var MIN_POPULATION = 4e-3;
|
|
@@ -346,26 +350,47 @@ function pickBest(items, score) {
|
|
|
346
350
|
return best;
|
|
347
351
|
}
|
|
348
352
|
var round3 = (value) => Math.round(value * 1e3) / 1e3;
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
+
function skinLikeness({ c, h, l }) {
|
|
354
|
+
return (1 - smoothstep(12, 26, hueDistance(h, 54))) * smoothstep(0.02, 0.035, c) * (1 - smoothstep(0.11, 0.15, c)) * smoothstep(0.26, 0.38, l) * (1 - smoothstep(0.88, 0.95, l));
|
|
355
|
+
}
|
|
356
|
+
var warmth = (h) => 1 - smoothstep(22, 50, hueDistance(h, 42));
|
|
357
|
+
var salience = (color) => 1 - 0.65 * skinLikeness(color);
|
|
358
|
+
var roleChroma = (source, { cap, gain }) => Math.min(
|
|
359
|
+
cap * (1 - 0.3 * warmth(source.h)),
|
|
360
|
+
// A faint tint is raised further, so it still reads as a colour.
|
|
361
|
+
Math.max(source.c * gain, Math.min(0.05, source.c * 1.6)) * (1 - 0.3 * skinLikeness(source))
|
|
362
|
+
);
|
|
363
|
+
var fitTone = (h, l, c) => ({
|
|
364
|
+
c: Math.max(0, Math.min(c, maxChroma(l, h) * 0.96)),
|
|
365
|
+
h,
|
|
366
|
+
l
|
|
367
|
+
});
|
|
368
|
+
function buildSwatch(tone, population, fromImage, minContrast) {
|
|
369
|
+
const room = maxChroma(tone.l, tone.h) * 0.96;
|
|
370
|
+
const rel = room > 0 ? tone.c / room : 0;
|
|
353
371
|
const ramp = {};
|
|
354
372
|
for (const step of AMBIENT_TONES) {
|
|
355
|
-
ramp[step] = formatOklch(toneOf(h, step / 100, rel,
|
|
373
|
+
ramp[step] = formatOklch(toneOf(tone.h, step / 100, rel, Math.max(tone.c, 0.04)));
|
|
356
374
|
}
|
|
357
375
|
return {
|
|
358
376
|
c: round3(tone.c),
|
|
359
377
|
color: formatOklch(tone),
|
|
360
378
|
fromImage,
|
|
361
|
-
h: Math.round(h * 10) / 10,
|
|
379
|
+
h: Math.round(tone.h * 10) / 10,
|
|
362
380
|
l: round3(tone.l),
|
|
363
381
|
on: formatOklch(onColorFor(tone, minContrast)),
|
|
364
|
-
population: round3(
|
|
382
|
+
population: round3(population),
|
|
365
383
|
ramp
|
|
366
384
|
};
|
|
367
385
|
}
|
|
368
|
-
|
|
386
|
+
function roleTone(source, spec, fallback, dilution = 1) {
|
|
387
|
+
if (!source) return fitTone(fallback.h, clamp(fallback.l, spec.min, spec.max), fallback.c);
|
|
388
|
+
return fitTone(
|
|
389
|
+
source.h,
|
|
390
|
+
clamp(source.l, spec.min, spec.max),
|
|
391
|
+
roleChroma(source, spec) * dilution
|
|
392
|
+
);
|
|
393
|
+
}
|
|
369
394
|
function clusterAmbientPixels(pixels, options) {
|
|
370
395
|
const { data, width, height } = pixels;
|
|
371
396
|
const bounds = options.letterbox ? findContentBounds(pixels) : { bottom: height, left: 0, right: width, top: 0 };
|
|
@@ -437,18 +462,23 @@ function clusterAmbientPixels(pixels, options) {
|
|
|
437
462
|
points[i * 3 + 2] = b;
|
|
438
463
|
weights[i] = w * (1 + 5 * Math.sqrt(a * a + b * b));
|
|
439
464
|
});
|
|
440
|
-
const { assignment,
|
|
441
|
-
const
|
|
442
|
-
members.forEach((bin, i) =>
|
|
465
|
+
const { assignment, k } = kmeans(points, weights, budgets[group]);
|
|
466
|
+
const sums = new Float64Array(k * 4);
|
|
467
|
+
members.forEach((bin, i) => {
|
|
468
|
+
for (let channel = 0; channel < 4; channel++) {
|
|
469
|
+
sums[assignment[i] * 4 + channel] += binSums[bin * 4 + channel];
|
|
470
|
+
}
|
|
471
|
+
});
|
|
443
472
|
const index = new Int32Array(k).fill(-1);
|
|
444
473
|
for (let j = 0; j < k; j++) {
|
|
445
|
-
|
|
446
|
-
|
|
474
|
+
const pop = sums[j * 4 + 3];
|
|
475
|
+
if (pop <= 0) continue;
|
|
476
|
+
const lch = labToLch([sums[j * 4] / pop, sums[j * 4 + 1] / pop, sums[j * 4 + 2] / pop]);
|
|
447
477
|
const room = maxChroma(lch.l, lch.h);
|
|
448
478
|
index[j] = clusters.length;
|
|
449
479
|
clusters.push({
|
|
450
480
|
...lch,
|
|
451
|
-
pop: pop
|
|
481
|
+
pop: pop / total,
|
|
452
482
|
rel: room > 0 ? clamp(lch.c / room, 0, 1) : 0,
|
|
453
483
|
rely: reliability(lch.l)
|
|
454
484
|
});
|
|
@@ -456,20 +486,26 @@ function clusterAmbientPixels(pixels, options) {
|
|
|
456
486
|
members.forEach((bin, i) => clusterOfBin[bin] = index[assignment[i]]);
|
|
457
487
|
});
|
|
458
488
|
const regionWeights = AMBIENT_REGIONS.map(() => new Float64Array(clusters.length));
|
|
489
|
+
const regionLab = AMBIENT_REGIONS.map(() => new Float64Array(clusters.length * 3));
|
|
459
490
|
for (let i = 0; i < pixelBins.length; i++) {
|
|
460
491
|
const bin = pixelBins[i];
|
|
461
492
|
if (bin < 0) continue;
|
|
462
493
|
const cluster = clusterOfBin[bin];
|
|
463
494
|
const bits = pixelRegions[i];
|
|
495
|
+
const w = binSums[bin * 4 + 3];
|
|
464
496
|
AMBIENT_REGIONS.forEach((region, r) => {
|
|
465
|
-
if (bits & REGION_BITS[region])
|
|
497
|
+
if (!(bits & REGION_BITS[region])) return;
|
|
498
|
+
regionWeights[r][cluster] += 1;
|
|
499
|
+
for (let channel = 0; channel < 3; channel++) {
|
|
500
|
+
regionLab[r][cluster * 3 + channel] += binSums[bin * 4 + channel] / w;
|
|
501
|
+
}
|
|
466
502
|
});
|
|
467
503
|
}
|
|
468
|
-
return { clusters, meanL, regionWeights };
|
|
504
|
+
return { clusters, meanL, regionLab, regionWeights };
|
|
469
505
|
}
|
|
470
506
|
function analyzeAmbientPixels(pixels, overrides = {}) {
|
|
471
507
|
const options = { ...DEFAULT_ANALYSIS, ...overrides };
|
|
472
|
-
const { clusters, meanL, regionWeights } = clusterAmbientPixels(pixels, options);
|
|
508
|
+
const { clusters, meanL, regionLab, regionWeights } = clusterAmbientPixels(pixels, options);
|
|
473
509
|
const chromatic = clusters.filter(isChromatic);
|
|
474
510
|
const presence = chromatic.reduce(
|
|
475
511
|
(sum, cluster) => sum + cluster.pop * colorfulness(cluster.c) * cluster.rely,
|
|
@@ -478,7 +514,7 @@ function analyzeAmbientPixels(pixels, overrides = {}) {
|
|
|
478
514
|
const neutral = presence < MIN_PRESENCE;
|
|
479
515
|
const dilution = 0.55 + 0.45 * Math.min(1, presence / 0.25);
|
|
480
516
|
const { minContrast, minHueDistance } = options;
|
|
481
|
-
const grey = { h: 0, l: clamp(meanL, 0.3, 0.8) };
|
|
517
|
+
const grey = { c: 0, h: 0, l: clamp(meanL, 0.3, 0.8) };
|
|
482
518
|
const family = /* @__PURE__ */ new Map();
|
|
483
519
|
for (const cluster of chromatic) {
|
|
484
520
|
let share2 = 0;
|
|
@@ -488,69 +524,62 @@ function analyzeAmbientPixels(pixels, overrides = {}) {
|
|
|
488
524
|
family.set(cluster, share2);
|
|
489
525
|
}
|
|
490
526
|
const share = (cluster) => family.get(cluster) ?? cluster.pop;
|
|
491
|
-
const
|
|
492
|
-
|
|
527
|
+
const dominantPick = neutral ? null : pickBest(
|
|
528
|
+
chromatic,
|
|
529
|
+
(cluster) => share(cluster) * cluster.c * cluster.rely * salience(cluster)
|
|
530
|
+
);
|
|
493
531
|
const vividPick = neutral ? null : pickBest(
|
|
494
532
|
chromatic.filter((cluster) => share(cluster) >= MIN_POPULATION),
|
|
495
|
-
(cluster) => cluster.c * cluster.c * Math.pow(share(cluster), 0.3) * cluster.rely
|
|
533
|
+
(cluster) => cluster.c * cluster.c * Math.pow(share(cluster), 0.3) * cluster.rely * salience(cluster)
|
|
496
534
|
);
|
|
497
535
|
const accentPick = pickBest(
|
|
498
536
|
chromatic.filter(
|
|
499
537
|
(cluster) => neutral ? share(cluster) >= 6e-3 && cluster.c >= 0.06 : share(cluster) >= MIN_POPULATION && cluster.c >= 0.035 && (!dominantPick || hueDistance(cluster.h, dominantPick.h) >= minHueDistance)
|
|
500
538
|
),
|
|
501
|
-
(cluster) => Math.pow(share(cluster), 0.6) * cluster.c * cluster.rely
|
|
539
|
+
(cluster) => Math.pow(share(cluster), 0.6) * cluster.c * cluster.rely * salience(cluster)
|
|
502
540
|
);
|
|
503
541
|
const mutedPick = neutral ? null : pickBest(
|
|
504
542
|
chromatic.filter((cluster) => cluster.c <= 0.09),
|
|
505
543
|
(cluster) => share(cluster) * cluster.rely * (1 - cluster.c / 0.12)
|
|
506
544
|
);
|
|
507
545
|
const dominantHue = dominantPick?.h ?? vividPick?.h ?? 0;
|
|
546
|
+
const accentSource = accentPick ?? vividPick;
|
|
508
547
|
const roles = {
|
|
509
548
|
dominant: buildSwatch(
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
cap: 0.22,
|
|
513
|
-
max: 0.74,
|
|
514
|
-
min: 0.42,
|
|
515
|
-
rel: dominantPick ? lift(dominantPick.rel, 0.25, 0.85, 0.9) : 0
|
|
516
|
-
},
|
|
517
|
-
grey,
|
|
549
|
+
roleTone(dominantPick, { cap: 0.2, gain: 1.15, max: 0.74, min: 0.42 }, grey),
|
|
550
|
+
dominantPick ? share(dominantPick) : 0,
|
|
518
551
|
true,
|
|
519
552
|
minContrast
|
|
520
553
|
),
|
|
521
554
|
vibrant: buildSwatch(
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
cap: 0.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
{ h: dominantHue, l: 0.78 },
|
|
555
|
+
roleTone(
|
|
556
|
+
vividPick,
|
|
557
|
+
{ cap: 0.22, gain: 1.35, max: 0.84, min: 0.62 },
|
|
558
|
+
{ c: 0, h: dominantHue, l: 0.78 },
|
|
559
|
+
dilution
|
|
560
|
+
),
|
|
561
|
+
vividPick ? share(vividPick) : 0,
|
|
530
562
|
true,
|
|
531
563
|
minContrast
|
|
532
564
|
),
|
|
533
565
|
muted: buildSwatch(
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
cap: 0.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
},
|
|
541
|
-
{ h: dominantHue, l: clamp(meanL, 0.38, 0.66) },
|
|
566
|
+
roleTone(
|
|
567
|
+
mutedPick,
|
|
568
|
+
{ cap: 0.07, gain: 1, max: 0.66, min: 0.38 },
|
|
569
|
+
{ c: dominantPick ? 0.035 : 0, h: dominantHue, l: clamp(meanL, 0.38, 0.66) }
|
|
570
|
+
),
|
|
571
|
+
mutedPick ? share(mutedPick) : 0,
|
|
542
572
|
Boolean(mutedPick) || neutral,
|
|
543
573
|
minContrast
|
|
544
574
|
),
|
|
545
575
|
accent: buildSwatch(
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
cap: 0.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
{ h: dominantHue, l: 0.72 },
|
|
576
|
+
roleTone(
|
|
577
|
+
accentSource,
|
|
578
|
+
{ cap: 0.22, gain: 1.3, max: 0.8, min: 0.55 },
|
|
579
|
+
{ c: 0, h: dominantHue, l: 0.72 },
|
|
580
|
+
dilution
|
|
581
|
+
),
|
|
582
|
+
accentSource ? share(accentSource) : 0,
|
|
554
583
|
Boolean(accentPick),
|
|
555
584
|
minContrast
|
|
556
585
|
)
|
|
@@ -567,35 +596,39 @@ function analyzeAmbientPixels(pixels, overrides = {}) {
|
|
|
567
596
|
options.shadowLightness - 0.02,
|
|
568
597
|
options.shadowLightness + 0.02
|
|
569
598
|
);
|
|
570
|
-
const shadow = deepSource ? toneOf(deepSource.h, shadowL,
|
|
599
|
+
const shadow = deepSource ? toneOf(deepSource.h, shadowL, clamp(0.3 + 0.7 * deepSource.rel, 0, 0.85), 0.1) : { c: 0, h: 0, l: shadowL };
|
|
571
600
|
const regions = {};
|
|
572
601
|
AMBIENT_REGIONS.forEach((region, r) => {
|
|
573
602
|
const weights = regionWeights[r];
|
|
603
|
+
const lab = regionLab[r];
|
|
574
604
|
let regionTotal = 0;
|
|
575
605
|
let regionL = 0;
|
|
576
606
|
clusters.forEach((cluster, j) => {
|
|
577
607
|
regionTotal += weights[j];
|
|
578
608
|
regionL += cluster.l * weights[j];
|
|
579
609
|
});
|
|
580
|
-
const share2 = (j) => regionTotal > 0 ? weights[j] / regionTotal : 0;
|
|
581
610
|
let strength = 0;
|
|
582
611
|
let pick = null;
|
|
583
612
|
let pickScore = 0;
|
|
584
|
-
clusters.forEach((
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
const
|
|
613
|
+
clusters.forEach((_, j) => {
|
|
614
|
+
const count = weights[j];
|
|
615
|
+
if (count <= 0) return;
|
|
616
|
+
const local = labToLch([lab[j * 3] / count, lab[j * 3 + 1] / count, lab[j * 3 + 2] / count]);
|
|
617
|
+
const rely = reliability(local.l);
|
|
618
|
+
if (local.c < MIN_CHROMA || rely <= 0) return;
|
|
619
|
+
const part = count / regionTotal;
|
|
620
|
+
strength += part * colorfulness(local.c) * rely;
|
|
621
|
+
const score = part * local.c * rely * salience(local);
|
|
588
622
|
if (score > pickScore) {
|
|
589
623
|
pickScore = score;
|
|
590
|
-
pick =
|
|
624
|
+
pick = local;
|
|
591
625
|
}
|
|
592
626
|
});
|
|
593
627
|
const chosen = neutral || strength < MIN_PRESENCE ? null : pick;
|
|
594
|
-
const tone = chosen ?
|
|
628
|
+
const tone = chosen ? fitTone(
|
|
595
629
|
chosen.h,
|
|
596
630
|
clamp(chosen.l, 0.42, 0.72),
|
|
597
|
-
|
|
598
|
-
0.22
|
|
631
|
+
roleChroma(chosen, { cap: 0.18, gain: 1.15 })
|
|
599
632
|
) : {
|
|
600
633
|
c: 0,
|
|
601
634
|
h: 0,
|
|
@@ -896,20 +929,63 @@ function normalizeColorMap(colors) {
|
|
|
896
929
|
}
|
|
897
930
|
return result;
|
|
898
931
|
}
|
|
899
|
-
|
|
900
|
-
|
|
932
|
+
var layersOf = /* @__PURE__ */ new WeakMap();
|
|
933
|
+
function paint(element, state, names) {
|
|
934
|
+
for (const name of names) {
|
|
935
|
+
let value;
|
|
936
|
+
for (let i = state.layers.length - 1; i >= 0 && value === void 0; i--) {
|
|
937
|
+
value = state.layers[i].vars[name];
|
|
938
|
+
}
|
|
939
|
+
if (value !== void 0) {
|
|
940
|
+
element.style.setProperty(name, value);
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
943
|
+
const base = state.base.get(name);
|
|
944
|
+
if (base?.value) element.style.setProperty(name, base.value, base.priority);
|
|
945
|
+
else element.style.removeProperty(name);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function removeLayer(element, state, layer) {
|
|
949
|
+
const index = state.layers.indexOf(layer);
|
|
950
|
+
if (index < 0) return;
|
|
951
|
+
if (layer.leaving) clearTimeout(layer.leaving);
|
|
952
|
+
state.layers.splice(index, 1);
|
|
953
|
+
paint(element, state, Object.keys(layer.vars));
|
|
954
|
+
if (state.layers.length === 0) layersOf.delete(element);
|
|
955
|
+
}
|
|
956
|
+
function applyScopedCssVariables(element, varMap, { linger = 0 } = {}) {
|
|
957
|
+
const vars = {};
|
|
901
958
|
for (const [name, value] of Object.entries(varMap)) {
|
|
902
|
-
if (
|
|
903
|
-
|
|
959
|
+
if (name && value) vars[name] = value;
|
|
960
|
+
}
|
|
961
|
+
let state = layersOf.get(element);
|
|
962
|
+
if (!state) {
|
|
963
|
+
state = { base: /* @__PURE__ */ new Map(), layers: [] };
|
|
964
|
+
layersOf.set(element, state);
|
|
965
|
+
}
|
|
966
|
+
for (const layer2 of state.layers.filter((layer3) => layer3.leaving)) {
|
|
967
|
+
removeLayer(element, state, layer2);
|
|
968
|
+
}
|
|
969
|
+
if (!layersOf.has(element)) layersOf.set(element, state);
|
|
970
|
+
for (const name of Object.keys(vars)) {
|
|
971
|
+
if (state.base.has(name)) continue;
|
|
972
|
+
state.base.set(name, {
|
|
904
973
|
priority: element.style.getPropertyPriority(name),
|
|
905
974
|
value: element.style.getPropertyValue(name)
|
|
906
975
|
});
|
|
907
|
-
element.style.setProperty(name, value);
|
|
908
976
|
}
|
|
977
|
+
const layer = { leaving: null, vars };
|
|
978
|
+
state.layers.push(layer);
|
|
979
|
+
paint(element, state, Object.keys(vars));
|
|
980
|
+
const owner = state;
|
|
981
|
+
let released = false;
|
|
909
982
|
return () => {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
983
|
+
if (released) return;
|
|
984
|
+
released = true;
|
|
985
|
+
if (linger > 0 && element.isConnected) {
|
|
986
|
+
layer.leaving = setTimeout(() => removeLayer(element, owner, layer), linger);
|
|
987
|
+
} else {
|
|
988
|
+
removeLayer(element, owner, layer);
|
|
913
989
|
}
|
|
914
990
|
};
|
|
915
991
|
}
|
|
@@ -983,6 +1059,7 @@ function useAmbientTheme(config = null) {
|
|
|
983
1059
|
cssVars = null,
|
|
984
1060
|
image = null,
|
|
985
1061
|
initialPalette = null,
|
|
1062
|
+
linger,
|
|
986
1063
|
options = null,
|
|
987
1064
|
scope: scope2 = null,
|
|
988
1065
|
transition = true
|
|
@@ -1028,14 +1105,16 @@ function useAmbientTheme(config = null) {
|
|
|
1028
1105
|
if (transition) {
|
|
1029
1106
|
targetEl.classList.add(...transitionKey.split(" ").filter(Boolean));
|
|
1030
1107
|
}
|
|
1031
|
-
const restoreVariables = applyScopedCssVariables(targetEl, resolvedVarMap
|
|
1108
|
+
const restoreVariables = applyScopedCssVariables(targetEl, resolvedVarMap, {
|
|
1109
|
+
linger: linger ?? (scope2 ? 0 : getAmbientSettings().linger)
|
|
1110
|
+
});
|
|
1032
1111
|
return () => {
|
|
1033
1112
|
restoreVariables();
|
|
1034
1113
|
if (transition && scope2) {
|
|
1035
1114
|
targetEl.classList.remove(...transitionKey.split(" ").filter(Boolean));
|
|
1036
1115
|
}
|
|
1037
1116
|
};
|
|
1038
|
-
}, [resolvedVarMap, scope2, transition, transitionKey]);
|
|
1117
|
+
}, [linger, resolvedVarMap, scope2, transition, transitionKey]);
|
|
1039
1118
|
return { isExtracting, palette: extractedPalette };
|
|
1040
1119
|
}
|
|
1041
1120
|
function useAmbient(configOrImage) {
|
|
@@ -1134,6 +1213,6 @@ function defineAmbient(definition = {}) {
|
|
|
1134
1213
|
});
|
|
1135
1214
|
}
|
|
1136
1215
|
|
|
1137
|
-
export { AMBIENT_REGIONS, AMBIENT_ROLES, AMBIENT_TONES, AmbientContext, AmbientProvider, DEFAULT_ANALYSIS, DEFAULT_CSS_VAR_NAMES, ambientModule, ambientTheme, analyzeAmbientPixels, applyScopedCssVariables, configureAmbient, contrastRatio, defineAmbient, extractPaletteFromImage, findContentBounds, formatOklch, getAmbientSettings, getCachedAmbientPalette, maxChroma, normalizeColorMap, onColorFor, paletteVarMap, primeAmbientPalette, resolveAmbientVarMap, resolveCssVarNames, resolvePageAmbientTheme, resolveTargetElement, srgbToOklab, toneOf, useAmbient, useAmbientColor, useAmbientTheme };
|
|
1138
|
-
//# sourceMappingURL=chunk-
|
|
1139
|
-
//# sourceMappingURL=chunk-
|
|
1216
|
+
export { AMBIENT_ANALYSIS_VERSION, AMBIENT_REGIONS, AMBIENT_ROLES, AMBIENT_TONES, AmbientContext, AmbientProvider, DEFAULT_ANALYSIS, DEFAULT_CSS_VAR_NAMES, DEFAULT_LINGER_MS, ambientModule, ambientTheme, analyzeAmbientPixels, applyScopedCssVariables, configureAmbient, contrastRatio, defineAmbient, extractPaletteFromImage, findContentBounds, formatOklch, getAmbientSettings, getCachedAmbientPalette, maxChroma, normalizeColorMap, onColorFor, paletteVarMap, primeAmbientPalette, resolveAmbientVarMap, resolveCssVarNames, resolvePageAmbientTheme, resolveTargetElement, skinLikeness, srgbToOklab, toneOf, useAmbient, useAmbientColor, useAmbientTheme };
|
|
1217
|
+
//# sourceMappingURL=chunk-TG6NMHXI.js.map
|
|
1218
|
+
//# sourceMappingURL=chunk-TG6NMHXI.js.map
|