@bhsd/codemirror-css-color-picker 6.3.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/dist/index.cjs ADDED
@@ -0,0 +1,606 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var view = require('@codemirror/view');
6
+ var common = require('@lezer/common');
7
+ var language = require('@codemirror/language');
8
+
9
+ const namedColors = new Map([
10
+ ['aliceblue', '#f0f8ff'],
11
+ ['antiquewhite', '#faebd7'],
12
+ ['aqua', '#00ffff'],
13
+ ['aquamarine', '#7fffd4'],
14
+ ['azure', '#f0ffff'],
15
+ ['beige', '#f5f5dc'],
16
+ ['bisque', '#ffe4c4'],
17
+ ['black', '#000000'],
18
+ ['blanchedalmond', '#ffebcd'],
19
+ ['blue', '#0000ff'],
20
+ ['blueviolet', '#8a2be2'],
21
+ ['brown', '#a52a2a'],
22
+ ['burlywood', '#deb887'],
23
+ ['cadetblue', '#5f9ea0'],
24
+ ['chartreuse', '#7fff00'],
25
+ ['chocolate', '#d2691e'],
26
+ ['coral', '#ff7f50'],
27
+ ['cornflowerblue', '#6495ed'],
28
+ ['cornsilk', '#fff8dc'],
29
+ ['crimson', '#dc143c'],
30
+ ['cyan', '#00ffff'],
31
+ ['darkblue', '#00008b'],
32
+ ['darkcyan', '#008b8b'],
33
+ ['darkgoldenrod', '#b8860b'],
34
+ ['darkgray', '#a9a9a9'],
35
+ ['darkgreen', '#006400'],
36
+ ['darkgrey', '#a9a9a9'],
37
+ ['darkkhaki', '#bdb76b'],
38
+ ['darkmagenta', '#8b008b'],
39
+ ['darkolivegreen', '#556b2f'],
40
+ ['darkorange', '#ff8c00'],
41
+ ['darkorchid', '#9932cc'],
42
+ ['darkred', '#8b0000'],
43
+ ['darksalmon', '#e9967a'],
44
+ ['darkseagreen', '#8fbc8f'],
45
+ ['darkslateblue', '#483d8b'],
46
+ ['darkslategray', '#2f4f4f'],
47
+ ['darkslategrey', '#2f4f4f'],
48
+ ['darkturquoise', '#00ced1'],
49
+ ['darkviolet', '#9400d3'],
50
+ ['deeppink', '#ff1493'],
51
+ ['deepskyblue', '#00bfff'],
52
+ ['dimgray', '#696969'],
53
+ ['dimgrey', '#696969'],
54
+ ['dodgerblue', '#1e90ff'],
55
+ ['firebrick', '#b22222'],
56
+ ['floralwhite', '#fffaf0'],
57
+ ['forestgreen', '#228b22'],
58
+ ['fuchsia', '#ff00ff'],
59
+ ['gainsboro', '#dcdcdc'],
60
+ ['ghostwhite', '#f8f8ff'],
61
+ ['goldenrod', '#daa520'],
62
+ ['gold', '#ffd700'],
63
+ ['gray', '#808080'],
64
+ ['green', '#008000'],
65
+ ['greenyellow', '#adff2f'],
66
+ ['grey', '#808080'],
67
+ ['honeydew', '#f0fff0'],
68
+ ['hotpink', '#ff69b4'],
69
+ ['indianred', '#cd5c5c'],
70
+ ['indigo', '#4b0082'],
71
+ ['ivory', '#fffff0'],
72
+ ['khaki', '#f0e68c'],
73
+ ['lavenderblush', '#fff0f5'],
74
+ ['lavender', '#e6e6fa'],
75
+ ['lawngreen', '#7cfc00'],
76
+ ['lemonchiffon', '#fffacd'],
77
+ ['lightblue', '#add8e6'],
78
+ ['lightcoral', '#f08080'],
79
+ ['lightcyan', '#e0ffff'],
80
+ ['lightgoldenrodyellow', '#fafad2'],
81
+ ['lightgray', '#d3d3d3'],
82
+ ['lightgreen', '#90ee90'],
83
+ ['lightgrey', '#d3d3d3'],
84
+ ['lightpink', '#ffb6c1'],
85
+ ['lightsalmon', '#ffa07a'],
86
+ ['lightseagreen', '#20b2aa'],
87
+ ['lightskyblue', '#87cefa'],
88
+ ['lightslategray', '#778899'],
89
+ ['lightslategrey', '#778899'],
90
+ ['lightsteelblue', '#b0c4de'],
91
+ ['lightyellow', '#ffffe0'],
92
+ ['lime', '#00ff00'],
93
+ ['limegreen', '#32cd32'],
94
+ ['linen', '#faf0e6'],
95
+ ['magenta', '#ff00ff'],
96
+ ['maroon', '#800000'],
97
+ ['mediumaquamarine', '#66cdaa'],
98
+ ['mediumblue', '#0000cd'],
99
+ ['mediumorchid', '#ba55d3'],
100
+ ['mediumpurple', '#9370db'],
101
+ ['mediumseagreen', '#3cb371'],
102
+ ['mediumslateblue', '#7b68ee'],
103
+ ['mediumspringgreen', '#00fa9a'],
104
+ ['mediumturquoise', '#48d1cc'],
105
+ ['mediumvioletred', '#c71585'],
106
+ ['midnightblue', '#191970'],
107
+ ['mintcream', '#f5fffa'],
108
+ ['mistyrose', '#ffe4e1'],
109
+ ['moccasin', '#ffe4b5'],
110
+ ['navajowhite', '#ffdead'],
111
+ ['navy', '#000080'],
112
+ ['oldlace', '#fdf5e6'],
113
+ ['olive', '#808000'],
114
+ ['olivedrab', '#6b8e23'],
115
+ ['orange', '#ffa500'],
116
+ ['orangered', '#ff4500'],
117
+ ['orchid', '#da70d6'],
118
+ ['palegoldenrod', '#eee8aa'],
119
+ ['palegreen', '#98fb98'],
120
+ ['paleturquoise', '#afeeee'],
121
+ ['palevioletred', '#db7093'],
122
+ ['papayawhip', '#ffefd5'],
123
+ ['peachpuff', '#ffdab9'],
124
+ ['peru', '#cd853f'],
125
+ ['pink', '#ffc0cb'],
126
+ ['plum', '#dda0dd'],
127
+ ['powderblue', '#b0e0e6'],
128
+ ['purple', '#800080'],
129
+ ['rebeccapurple', '#663399'],
130
+ ['red', '#ff0000'],
131
+ ['rosybrown', '#bc8f8f'],
132
+ ['royalblue', '#4169e1'],
133
+ ['saddlebrown', '#8b4513'],
134
+ ['salmon', '#fa8072'],
135
+ ['sandybrown', '#f4a460'],
136
+ ['seagreen', '#2e8b57'],
137
+ ['seashell', '#fff5ee'],
138
+ ['sienna', '#a0522d'],
139
+ ['silver', '#c0c0c0'],
140
+ ['skyblue', '#87ceeb'],
141
+ ['slateblue', '#6a5acd'],
142
+ ['slategray', '#708090'],
143
+ ['slategrey', '#708090'],
144
+ ['snow', '#fffafa'],
145
+ ['springgreen', '#00ff7f'],
146
+ ['steelblue', '#4682b4'],
147
+ ['tan', '#d2b48c'],
148
+ ['teal', '#008080'],
149
+ ['thistle', '#d8bfd8'],
150
+ ['tomato', '#ff6347'],
151
+ ['turquoise', '#40e0d0'],
152
+ ['violet', '#ee82ee'],
153
+ ['wheat', '#f5deb3'],
154
+ ['white', '#ffffff'],
155
+ ['whitesmoke', '#f5f5f5'],
156
+ ['yellow', '#ffff00'],
157
+ ['yellowgreen', '#9acd32'],
158
+ ]);
159
+
160
+ var __rest = (undefined && undefined.__rest) || function (s, e) {
161
+ var t = {};
162
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
163
+ t[p] = s[p];
164
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
165
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
166
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
167
+ t[p[i]] = s[p[i]];
168
+ }
169
+ return t;
170
+ };
171
+ const pickerState = new WeakMap();
172
+ exports.ColorType = void 0;
173
+ (function (ColorType) {
174
+ ColorType["rgb"] = "RGB";
175
+ ColorType["hex"] = "HEX";
176
+ ColorType["named"] = "NAMED";
177
+ ColorType["hsl"] = "HSL";
178
+ })(exports.ColorType || (exports.ColorType = {}));
179
+ const rgbCallExpRegex = /rgba?\(\s*(\d{1,3}%?)\s*[,\s]\s*(\d{1,3}%?)\s*[,\s]\s*(\d{1,3}%?)\s*([,/]\s*0?\.?\d+%?)?\s*\)/;
180
+ const hslCallExpRegex = /hsla?\(\s*(\d{1,3})(?:deg)?\s*[,\s]\s*(\d{1,3})%?\s*[,\s]\s*(\d{1,3})%?\s*([,/]\s*0?\.?\d+%?)?\s*\)/;
181
+ const hexRegex = /(^|\b)(#[0-9a-f]{3,9})(\b|$)/i;
182
+ function discoverColorsInCSS(syntaxTree, from, to, typeName, doc, language) {
183
+ var _a;
184
+ switch (typeName) {
185
+ case 'AttributeValue': {
186
+ const innerTree = syntaxTree.resolveInner(from, 0).tree;
187
+ if (!innerTree) {
188
+ return null;
189
+ }
190
+ const overlayTree = (_a = innerTree.prop(common.NodeProp.mounted)) === null || _a === void 0 ? void 0 : _a.tree;
191
+ if ((overlayTree === null || overlayTree === void 0 ? void 0 : overlayTree.type.name) !== 'Styles') {
192
+ return null;
193
+ }
194
+ const ret = [];
195
+ overlayTree.iterate({
196
+ from: 0,
197
+ to: overlayTree.length,
198
+ enter: ({ type, from: overlayFrom, to: overlayTo }) => {
199
+ const maybeWidgetOptions = discoverColorsInCSS(syntaxTree,
200
+ // We add one because the tree doesn't include the
201
+ // quotation mark from the style tag
202
+ from + 1 + overlayFrom, from + 1 + overlayTo, type.name, doc);
203
+ if (maybeWidgetOptions) {
204
+ if (Array.isArray(maybeWidgetOptions)) {
205
+ throw new Error('Unexpected nested overlays');
206
+ }
207
+ ret.push(maybeWidgetOptions);
208
+ }
209
+ },
210
+ });
211
+ return ret;
212
+ }
213
+ case 'CallExpression': {
214
+ const callExp = doc.sliceString(from, to);
215
+ const result = parseCallExpression(callExp);
216
+ if (!result) {
217
+ return null;
218
+ }
219
+ return Object.assign(Object.assign({}, result), { from,
220
+ to });
221
+ }
222
+ case 'ColorLiteral': {
223
+ const result = parseColorLiteral(doc.sliceString(from, to));
224
+ if (!result) {
225
+ return null;
226
+ }
227
+ return Object.assign(Object.assign({}, result), { from,
228
+ to });
229
+ }
230
+ case 'ValueName': {
231
+ const colorName = doc.sliceString(from, to);
232
+ const result = parseNamedColor(colorName);
233
+ if (!result) {
234
+ return null;
235
+ }
236
+ return Object.assign(Object.assign({}, result), { from,
237
+ to });
238
+ }
239
+ default:
240
+ return null;
241
+ }
242
+ }
243
+ function parseCallExpression(callExp) {
244
+ const fn = callExp.slice(0, 3);
245
+ switch (fn) {
246
+ case 'rgb': {
247
+ const match = rgbCallExpRegex.exec(callExp);
248
+ if (!match) {
249
+ return null;
250
+ }
251
+ const [_, r, g, b, a] = match;
252
+ const color = rgbToHex(r, g, b);
253
+ return {
254
+ colorType: exports.ColorType.rgb,
255
+ color,
256
+ alpha: (a === null || a === void 0 ? void 0 : a.replace(/^\//, ',')) || '',
257
+ };
258
+ }
259
+ case 'hsl': {
260
+ const match = hslCallExpRegex.exec(callExp);
261
+ if (!match) {
262
+ return null;
263
+ }
264
+ const [_, h, s, l, a] = match;
265
+ const color = hslToHex(h, s, l);
266
+ return {
267
+ colorType: exports.ColorType.hsl,
268
+ color,
269
+ alpha: (a === null || a === void 0 ? void 0 : a.replace(/^\//, ',')) || '',
270
+ };
271
+ }
272
+ default:
273
+ return null;
274
+ }
275
+ }
276
+ function parseColorLiteral(colorLiteral) {
277
+ const match = hexRegex.exec(colorLiteral);
278
+ if (!match) {
279
+ return null;
280
+ }
281
+ const [color, alpha] = toFullHex(colorLiteral);
282
+ return {
283
+ colorType: exports.ColorType.hex,
284
+ color,
285
+ alpha,
286
+ };
287
+ }
288
+ function parseNamedColor(colorName) {
289
+ const color = namedColors.get(colorName);
290
+ if (!color) {
291
+ return null;
292
+ }
293
+ return {
294
+ colorType: exports.ColorType.named,
295
+ color,
296
+ alpha: '',
297
+ };
298
+ }
299
+ function colorPickersDecorations(view$1, discoverColors) {
300
+ const widgets = [];
301
+ const st = language.syntaxTree(view$1.state);
302
+ for (const range of view$1.visibleRanges) {
303
+ st.iterate({
304
+ from: range.from,
305
+ to: range.to,
306
+ enter: ({ type, from, to }) => {
307
+ var _a;
308
+ const maybeWidgetOptions = discoverColors(st, from, to, type.name, view$1.state.doc, (_a = view$1.state.facet(language.language)) === null || _a === void 0 ? void 0 : _a.name);
309
+ if (!maybeWidgetOptions) {
310
+ return;
311
+ }
312
+ if (!Array.isArray(maybeWidgetOptions)) {
313
+ widgets.push(view.Decoration.widget({
314
+ widget: new ColorPickerWidget(maybeWidgetOptions),
315
+ side: 1,
316
+ }).range(maybeWidgetOptions.from));
317
+ return;
318
+ }
319
+ for (const wo of maybeWidgetOptions) {
320
+ widgets.push(view.Decoration.widget({
321
+ widget: new ColorPickerWidget(wo),
322
+ side: 1,
323
+ }).range(wo.from));
324
+ }
325
+ },
326
+ });
327
+ }
328
+ return view.Decoration.set(widgets);
329
+ }
330
+ function toFullHex(color) {
331
+ if (color.length === 4) {
332
+ // 3-char hex
333
+ return [
334
+ `#${color[1].repeat(2)}${color[2].repeat(2)}${color[3].repeat(2)}`,
335
+ '',
336
+ ];
337
+ }
338
+ if (color.length === 5) {
339
+ // 4-char hex (alpha)
340
+ return [
341
+ `#${color[1].repeat(2)}${color[2].repeat(2)}${color[3].repeat(2)}`,
342
+ color[4].repeat(2),
343
+ ];
344
+ }
345
+ if (color.length === 9) {
346
+ // 8-char hex (alpha)
347
+ return [`#${color.slice(1, -2)}`, color.slice(-2)];
348
+ }
349
+ return [color, ''];
350
+ }
351
+ function rgbComponentToHex(component) {
352
+ let numericValue;
353
+ if (component.endsWith('%')) {
354
+ // 0-100%
355
+ const percent = Number(component.slice(0, -1));
356
+ numericValue = Math.round((percent / 100) * 255.0);
357
+ }
358
+ else {
359
+ numericValue = Number(component); // assume 0-255
360
+ }
361
+ return decimalToHex(numericValue);
362
+ }
363
+ function decimalToHex(decimal) {
364
+ const hex = decimal.toString(16);
365
+ return hex.length === 1 ? '0' + hex : hex;
366
+ }
367
+ function hexToRGBComponents(hex) {
368
+ const r = hex.slice(1, 3);
369
+ const g = hex.slice(3, 5);
370
+ const b = hex.slice(5, 7);
371
+ return [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)];
372
+ }
373
+ function rgbToHex(r, g, b) {
374
+ return `#${rgbComponentToHex(r)}${rgbComponentToHex(g)}${rgbComponentToHex(b)}`;
375
+ }
376
+ function hslToHex(h, s, l) {
377
+ const sFloat = Number(s) / 100;
378
+ const lFloat = Number(l) / 100;
379
+ const [r, g, b] = hslToRGB(Number(h), sFloat, lFloat);
380
+ return `#${decimalToHex(r)}${decimalToHex(g)}${decimalToHex(b)}`;
381
+ }
382
+ function hslToRGB(hue, saturation, luminance) {
383
+ // If there is no Saturation it means that it’s a shade of grey.
384
+ // So in that case we just need to convert the Luminance and set R,G and B to that level.
385
+ if (saturation === 0) {
386
+ const value = Math.round(luminance * 255);
387
+ return [value, value, value];
388
+ }
389
+ let temp1;
390
+ // If Luminance is smaller then 0.5 (50%) then temporary_1 = Luminance x (1.0+Saturation)
391
+ if (luminance < 0.5) {
392
+ temp1 = luminance * (1.0 + saturation);
393
+ }
394
+ else {
395
+ // If Luminance is equal or larger then 0.5 (50%) then temporary_1 = Luminance + Saturation – Luminance x Saturation
396
+ temp1 = luminance + saturation - luminance * saturation;
397
+ }
398
+ // temporary_2 = 2 x Luminance – temporary _1
399
+ const temp2 = 2 * luminance - temp1;
400
+ // The next step is to convert the 360 degrees in a circle to 1 by dividing the angle by 360.
401
+ hue = hue / 360.0;
402
+ // And now we need another temporary variable for each color channel, temporary_R, temporary_G and temporary_B.
403
+ // All values need to be between 0 and 1. In our case all the values are between 0 and 1
404
+ const tempR = clamp(hue + 0.333);
405
+ const tempG = hue;
406
+ const tempB = clamp(hue - 0.333);
407
+ const red = hueToRGB(temp1, temp2, tempR);
408
+ const green = hueToRGB(temp1, temp2, tempG);
409
+ const blue = hueToRGB(temp1, temp2, tempB);
410
+ return [
411
+ Math.round(red * 255),
412
+ Math.round(green * 255),
413
+ Math.round(blue * 255),
414
+ ];
415
+ }
416
+ // If you get a negative value you need to add 1 to it.
417
+ // If you get a value above 1 you need to subtract 1 from it.
418
+ function clamp(num) {
419
+ if (num < 0) {
420
+ return num + 1;
421
+ }
422
+ if (num > 1) {
423
+ return num - 1;
424
+ }
425
+ return num;
426
+ }
427
+ /**
428
+ * Now we need to do up to 3 tests to select the correct formula for each color channel. Let’s start with Red.
429
+ *
430
+ * test 1 – If 6 x temporary_R is smaller then 1, Red = temporary_2 + (temporary_1 – temporary_2) x 6 x temporary_R
431
+ * In the case the first test is larger then 1 check the following
432
+ *
433
+ * test 2 – If 2 x temporary_R is smaller then 1, Red = temporary_1
434
+ * In the case the second test also is larger then 1 do the following
435
+ *
436
+ * test 3 – If 3 x temporary_R is smaller then 2, Red = temporary_2 + (temporary_1 – temporary_2) x (0.666 – temporary_R) x 6
437
+ * In the case the third test also is larger then 2 you do the following
438
+ *
439
+ * Red = temporary_2
440
+ */
441
+ function hueToRGB(temp1, temp2, tempHue) {
442
+ if (6 * tempHue < 1) {
443
+ return temp2 + (temp1 - temp2) * 6 * tempHue;
444
+ }
445
+ if (2 * tempHue < 1) {
446
+ return temp1;
447
+ }
448
+ if (3 * tempHue < 2) {
449
+ return temp2 + (temp1 - temp2) * (0.666 - tempHue) * 6;
450
+ }
451
+ return temp2;
452
+ }
453
+ // https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
454
+ function rgbToHSL(r, g, b) {
455
+ const redPercent = r / 255;
456
+ const greenPercent = g / 255;
457
+ const bluePercent = b / 255;
458
+ const min = Math.min(redPercent, greenPercent, bluePercent);
459
+ const max = Math.max(redPercent, greenPercent, bluePercent);
460
+ const luminance = (max + min) / 2;
461
+ // If the min and max value are the same, it means that there is no saturation. ...
462
+ // If there is no Saturation, we don’t need to calculate the Hue. So we set it to 0 degrees.
463
+ if (max === min) {
464
+ return [0, 0, luminance];
465
+ }
466
+ let saturation;
467
+ // If Luminance is less or equal to 0.5, then Saturation = (max-min)/(max+min)
468
+ if (luminance <= 0.5) {
469
+ saturation = (max - min) / (max + min);
470
+ }
471
+ else {
472
+ // If Luminance is bigger then 0.5. then Saturation = ( max-min)/(2.0-max-min)
473
+ saturation = (max - min) / (2.0 - max - min);
474
+ }
475
+ let hue;
476
+ // If Red is max, then Hue = (G-B)/(max-min)
477
+ if (max === redPercent) {
478
+ hue = (greenPercent - bluePercent) / (max - min);
479
+ }
480
+ else if (greenPercent === max) {
481
+ // If Green is max, then Hue = 2.0 + (B-R)/(max-min)
482
+ hue = 2.0 + (bluePercent - redPercent) / (max - min);
483
+ }
484
+ else {
485
+ // If Blue is max, then Hue = 4.0 + (R-G)/(max-min)
486
+ hue = 4.0 + (redPercent - greenPercent) / (max - min);
487
+ }
488
+ hue = Math.round(hue * 60); // convert to degrees
489
+ // make hue positive angle/degrees
490
+ while (hue < 0) {
491
+ hue += 360;
492
+ }
493
+ return [hue, saturation, luminance];
494
+ }
495
+ const wrapperClassName = 'cm-css-color-picker-wrapper';
496
+ class ColorPickerWidget extends view.WidgetType {
497
+ constructor(_a) {
498
+ var { color } = _a, state = __rest(_a, ["color"]);
499
+ super();
500
+ this.state = state;
501
+ this.color = color;
502
+ }
503
+ eq(other) {
504
+ return (other.state.colorType === this.state.colorType &&
505
+ other.color === this.color &&
506
+ other.state.from === this.state.from &&
507
+ other.state.to === this.state.to &&
508
+ other.state.alpha === this.state.alpha);
509
+ }
510
+ toDOM() {
511
+ const picker = document.createElement('input');
512
+ pickerState.set(picker, this.state);
513
+ picker.type = 'color';
514
+ picker.value = this.color;
515
+ const wrapper = document.createElement('span');
516
+ wrapper.appendChild(picker);
517
+ wrapper.className = wrapperClassName;
518
+ return wrapper;
519
+ }
520
+ ignoreEvent() {
521
+ return false;
522
+ }
523
+ }
524
+ const colorPickerTheme = view.EditorView.baseTheme({
525
+ [`.${wrapperClassName}`]: {
526
+ display: 'inline-block',
527
+ outline: '1px solid #eee',
528
+ marginRight: '0.6ch',
529
+ height: '1em',
530
+ width: '1em',
531
+ transform: 'translateY(1px)',
532
+ },
533
+ [`.${wrapperClassName} input[type="color"]`]: {
534
+ cursor: 'pointer',
535
+ height: '100%',
536
+ width: '100%',
537
+ padding: 0,
538
+ border: 'none',
539
+ '&::-webkit-color-swatch-wrapper': {
540
+ padding: 0,
541
+ },
542
+ '&::-webkit-color-swatch': {
543
+ border: 'none',
544
+ },
545
+ '&::-moz-color-swatch': {
546
+ border: 'none',
547
+ },
548
+ },
549
+ });
550
+ const makeColorPicker = (options) => view.ViewPlugin.fromClass(class ColorPickerViewPlugin {
551
+ constructor(view) {
552
+ this.decorations = colorPickersDecorations(view, options.discoverColors);
553
+ }
554
+ update(update) {
555
+ if (update.docChanged || update.viewportChanged) {
556
+ this.decorations = colorPickersDecorations(update.view, options.discoverColors);
557
+ }
558
+ }
559
+ }, {
560
+ decorations: (v) => v.decorations,
561
+ eventHandlers: {
562
+ change: (e, view) => {
563
+ const target = e.target;
564
+ if (target.nodeName !== 'INPUT' ||
565
+ !target.parentElement ||
566
+ !target.parentElement.classList.contains(wrapperClassName)) {
567
+ return false;
568
+ }
569
+ const data = pickerState.get(target);
570
+ let converted = target.value + data.alpha;
571
+ if (data.colorType === exports.ColorType.rgb) {
572
+ converted = `rgb(${hexToRGBComponents(target.value).join(', ')}${data.alpha})`;
573
+ }
574
+ else if (data.colorType === exports.ColorType.named) {
575
+ // If the hex is an exact match for another named color, prefer retaining name
576
+ for (const [key, value] of namedColors.entries()) {
577
+ if (value === target.value) {
578
+ converted = key;
579
+ }
580
+ }
581
+ }
582
+ else if (data.colorType === exports.ColorType.hsl) {
583
+ const [r, g, b] = hexToRGBComponents(target.value);
584
+ const [h, s, l] = rgbToHSL(r, g, b);
585
+ converted = `hsl(${h}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%${data.alpha})`;
586
+ }
587
+ view.dispatch({
588
+ changes: {
589
+ from: data.from,
590
+ to: data.to,
591
+ insert: converted,
592
+ },
593
+ });
594
+ return true;
595
+ },
596
+ },
597
+ });
598
+ const colorPicker = [makeColorPicker({ discoverColors: discoverColorsInCSS }), colorPickerTheme];
599
+
600
+ exports.colorPicker = colorPicker;
601
+ exports.colorPickerTheme = colorPickerTheme;
602
+ exports.makeColorPicker = makeColorPicker;
603
+ exports.parseCallExpression = parseCallExpression;
604
+ exports.parseColorLiteral = parseColorLiteral;
605
+ exports.parseNamedColor = parseNamedColor;
606
+ exports.wrapperClassName = wrapperClassName;
@@ -0,0 +1,36 @@
1
+ import { ViewPlugin, DecorationSet, ViewUpdate } from '@codemirror/view';
2
+ import { Extension, Text } from '@codemirror/state';
3
+ import { Tree } from '@lezer/common';
4
+
5
+ interface PickerState {
6
+ from: number;
7
+ to: number;
8
+ alpha: string;
9
+ colorType: ColorType;
10
+ }
11
+ interface WidgetOptions extends PickerState {
12
+ color: string;
13
+ }
14
+ type ColorData = Omit<WidgetOptions, 'from' | 'to'>;
15
+ declare enum ColorType {
16
+ rgb = "RGB",
17
+ hex = "HEX",
18
+ named = "NAMED",
19
+ hsl = "HSL"
20
+ }
21
+ declare function discoverColorsInCSS(syntaxTree: Tree, from: number, to: number, typeName: string, doc: Text, language?: string): WidgetOptions | Array<WidgetOptions> | null;
22
+ declare function parseCallExpression(callExp: string): ColorData | null;
23
+ declare function parseColorLiteral(colorLiteral: string): ColorData | null;
24
+ declare function parseNamedColor(colorName: string): ColorData | null;
25
+ declare const wrapperClassName = "cm-css-color-picker-wrapper";
26
+ declare const colorPickerTheme: Extension;
27
+ interface IFactoryOptions {
28
+ discoverColors: typeof discoverColorsInCSS;
29
+ }
30
+ declare const makeColorPicker: (options: IFactoryOptions) => ViewPlugin<{
31
+ decorations: DecorationSet;
32
+ update(update: ViewUpdate): void;
33
+ }>;
34
+ declare const colorPicker: Extension;
35
+
36
+ export { ColorData, ColorType, WidgetOptions, colorPicker, colorPickerTheme, makeColorPicker, parseCallExpression, parseColorLiteral, parseNamedColor, wrapperClassName };