@proyecto-viviana/solid-stately 0.4.0 → 0.4.1

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.
Files changed (33) hide show
  1. package/dist/calendar/createDateFieldState.d.ts +56 -18
  2. package/dist/calendar/createRangeCalendarState.d.ts +10 -0
  3. package/dist/calendar/createTimeFieldState.d.ts +38 -67
  4. package/dist/calendar/intl/index.d.ts +10 -0
  5. package/dist/collections/ListCollection.d.ts +8 -0
  6. package/dist/collections/createListState.d.ts +12 -0
  7. package/dist/collections/getChildNodes.d.ts +8 -0
  8. package/dist/collections/index.d.ts +2 -2
  9. package/dist/collections/types.d.ts +9 -0
  10. package/dist/color/intl/index.d.ts +14 -0
  11. package/dist/dnd/createDroppableCollectionState.d.ts +17 -2
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +3444 -1304
  14. package/dist/index.js.map +1 -1
  15. package/dist/selection/SelectionManager.d.ts +9 -0
  16. package/package.json +1 -1
  17. package/src/calendar/createCalendarState.ts +26 -4
  18. package/src/calendar/createDateFieldState.ts +614 -459
  19. package/src/calendar/createRangeCalendarState.ts +212 -11
  20. package/src/calendar/createTimeFieldState.ts +179 -467
  21. package/src/calendar/intl/index.ts +364 -0
  22. package/src/collections/ListCollection.ts +31 -0
  23. package/src/collections/createListState.ts +92 -1
  24. package/src/collections/getChildNodes.ts +31 -0
  25. package/src/collections/index.ts +3 -0
  26. package/src/collections/types.ts +10 -0
  27. package/src/color/Color.ts +104 -133
  28. package/src/color/intl/index.ts +1409 -0
  29. package/src/combobox/createComboBoxState.ts +30 -13
  30. package/src/dnd/createDroppableCollectionState.ts +125 -6
  31. package/src/index.ts +3 -0
  32. package/src/selection/SelectionManager.ts +15 -0
  33. package/src/steplist/createStepListState.ts +27 -4
@@ -16,6 +16,11 @@ import type {
16
16
  HSLColor,
17
17
  HSBColor,
18
18
  } from "./types";
19
+ import {
20
+ getColorStringForLocale,
21
+ formatColorMessage,
22
+ type ColorStringKey,
23
+ } from "./intl";
19
24
 
20
25
  // Channel ranges
21
26
  const RGB_CHANNEL_RANGE: ColorChannelRange = {
@@ -46,18 +51,6 @@ const PERCENT_CHANNEL_RANGE: ColorChannelRange = {
46
51
  pageSize: 10,
47
52
  };
48
53
 
49
- // Channel names (English only for now)
50
- const CHANNEL_NAMES: Record<ColorChannel, string> = {
51
- hue: "Hue",
52
- saturation: "Saturation",
53
- brightness: "Brightness",
54
- lightness: "Lightness",
55
- red: "Red",
56
- green: "Green",
57
- blue: "Blue",
58
- alpha: "Alpha",
59
- };
60
-
61
54
  // React Stately uses OKLCH for color names so that lightness is perceptually
62
55
  // consistent across hues.
63
56
  const ORANGE_LIGHTNESS_THRESHOLD = 0.68;
@@ -122,46 +115,36 @@ function rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: n
122
115
  }
123
116
  }
124
117
 
118
+ // 2-decimal precision mirrors upstream RGBColor.toHSL (toFixedNumber(_, 2)); the
119
+ // old integer rounding silently shifted converted hues by up to half a degree,
120
+ // which surfaced as a 1-LSB gradient divergence in ColorArea.
125
121
  return {
126
- h: Math.round(h * 360),
127
- s: Math.round(s * 100),
128
- l: Math.round(l * 100),
122
+ h: toFixed(h * 360, 2),
123
+ s: toFixed(s * 100, 2),
124
+ l: toFixed(l * 100, 2),
129
125
  };
130
126
  }
131
127
 
132
128
  /**
133
- * Convert HSL to RGB.
129
+ * Convert HSL to RGB. Mirrors upstream @react-stately/color HSLColor.toRGB
130
+ * bit-for-bit — the Wikipedia "HSL to RGB alternative" formula
131
+ * (https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative) — so the
132
+ * float64 LSB rounding matches the oracle exactly. The classic hue2rgb algorithm
133
+ * is equivalent in the reals but rounds a channel differently at .5 boundaries
134
+ * (e.g. hsl(50,100%,50%) green computes to 212.5 → 213 here, 212 upstream).
135
+ * h is in degrees [0,360]; s and l are percentages [0,100].
134
136
  */
135
137
  function hslToRgb(h: number, s: number, l: number): { r: number; g: number; b: number } {
136
- h /= 360;
137
- s /= 100;
138
- l /= 100;
139
-
140
- let r: number, g: number, b: number;
141
-
142
- if (s === 0) {
143
- r = g = b = l;
144
- } else {
145
- const hue2rgb = (p: number, q: number, t: number) => {
146
- if (t < 0) t += 1;
147
- if (t > 1) t -= 1;
148
- if (t < 1 / 6) return p + (q - p) * 6 * t;
149
- if (t < 1 / 2) return q;
150
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
151
- return p;
152
- };
153
-
154
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
155
- const p = 2 * l - q;
156
- r = hue2rgb(p, q, h + 1 / 3);
157
- g = hue2rgb(p, q, h);
158
- b = hue2rgb(p, q, h - 1 / 3);
159
- }
138
+ const saturation = s / 100;
139
+ const lightness = l / 100;
140
+ const a = saturation * Math.min(lightness, 1 - lightness);
141
+ const fn = (n: number, k = (n + h / 30) % 12) =>
142
+ lightness - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
160
143
 
161
144
  return {
162
- r: Math.round(r * 255),
163
- g: Math.round(g * 255),
164
- b: Math.round(b * 255),
145
+ r: Math.round(fn(0) * 255),
146
+ g: Math.round(fn(8) * 255),
147
+ b: Math.round(fn(4) * 255),
165
148
  };
166
149
  }
167
150
 
@@ -194,72 +177,38 @@ function rgbToHsb(r: number, g: number, b: number): { h: number; s: number; b: n
194
177
  }
195
178
  }
196
179
 
180
+ // 2-decimal precision mirrors upstream RGBColor.toHSB (toFixedNumber(_, 2)).
197
181
  return {
198
- h: Math.round(h * 360),
199
- s: Math.round(s * 100),
200
- b: Math.round(v * 100),
182
+ h: toFixed(h * 360, 2),
183
+ s: toFixed(s * 100, 2),
184
+ b: toFixed(v * 100, 2),
201
185
  };
202
186
  }
203
187
 
204
188
  /**
205
- * Convert HSB to RGB.
189
+ * Convert HSB (HSV) to RGB. Mirrors upstream @react-stately/color HSBColor.toRGB
190
+ * bit-for-bit — the Wikipedia "HSV to RGB alternative" formula
191
+ * (https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB_alternative) — so the
192
+ * float64 LSB rounding matches the oracle exactly. The classic sextant algorithm
193
+ * is equivalent in the reals but can round a channel differently at .5 boundaries.
194
+ * h is in degrees [0,360]; s and b are percentages [0,100].
206
195
  */
207
196
  function hsbToRgb(h: number, s: number, b: number): { r: number; g: number; b: number } {
208
- h /= 360;
209
- s /= 100;
210
- b /= 100;
211
-
212
- let r: number, g: number, bl: number;
213
-
214
- const i = Math.floor(h * 6);
215
- const f = h * 6 - i;
216
- const p = b * (1 - s);
217
- const q = b * (1 - f * s);
218
- const t = b * (1 - (1 - f) * s);
219
-
220
- switch (i % 6) {
221
- case 0:
222
- r = b;
223
- g = t;
224
- bl = p;
225
- break;
226
- case 1:
227
- r = q;
228
- g = b;
229
- bl = p;
230
- break;
231
- case 2:
232
- r = p;
233
- g = b;
234
- bl = t;
235
- break;
236
- case 3:
237
- r = p;
238
- g = q;
239
- bl = b;
240
- break;
241
- case 4:
242
- r = t;
243
- g = p;
244
- bl = b;
245
- break;
246
- default:
247
- r = b;
248
- g = p;
249
- bl = q;
250
- break;
251
- }
197
+ const saturation = s / 100;
198
+ const brightness = b / 100;
199
+ const fn = (n: number, k = (n + h / 60) % 6) =>
200
+ brightness - saturation * brightness * Math.max(Math.min(k, 4 - k, 1), 0);
252
201
 
253
202
  return {
254
- r: Math.round(r * 255),
255
- g: Math.round(g * 255),
256
- b: Math.round(bl * 255),
203
+ r: Math.round(fn(5) * 255),
204
+ g: Math.round(fn(3) * 255),
205
+ b: Math.round(fn(1) * 255),
257
206
  };
258
207
  }
259
208
 
260
- function getOklchHueName(l: number, c: number, h: number): [string, number] {
209
+ function getOklchHueName(l: number, c: number, h: number, locale: string): [string, number] {
261
210
  if (c < GRAY_THRESHOLD) {
262
- return ["gray", l];
211
+ return [getColorStringForLocale("gray", locale), l];
263
212
  }
264
213
 
265
214
  for (let i = 0; i < OKLCH_HUES.length; i += 1) {
@@ -280,27 +229,29 @@ function getOklchHueName(l: number, c: number, h: number): [string, number] {
280
229
  hueName = "yellow green";
281
230
  }
282
231
 
283
- return [hueName.toLocaleLowerCase(), l];
232
+ const name = getColorStringForLocale(hueName as ColorStringKey, locale).toLocaleLowerCase(
233
+ locale
234
+ );
235
+ return [name, l];
284
236
  }
285
237
  }
286
238
 
287
- return ["pink", l];
239
+ return [getColorStringForLocale("pink", locale).toLocaleLowerCase(locale), l];
288
240
  }
289
241
 
290
- function getColorNameFromColor(color: Color): string {
242
+ function getColorNameFromColor(color: Color, locale: string): string {
291
243
  let [l, c, h] = toOKLCH(color);
292
- const alpha = color.getChannelValue("alpha");
293
244
 
294
245
  if (l > 0.999) {
295
- return alpha < 1 ? `white ${Math.round((1 - alpha) * 100)}% transparent` : "white";
246
+ return getColorStringForLocale("white", locale);
296
247
  }
297
248
 
298
249
  if (l < 0.001) {
299
- return alpha < 1 ? `black ${Math.round((1 - alpha) * 100)}% transparent` : "black";
250
+ return getColorStringForLocale("black", locale);
300
251
  }
301
252
 
302
253
  let hue: string;
303
- [hue, l] = getOklchHueName(l, c, h);
254
+ [hue, l] = getOklchHueName(l, c, h, locale);
304
255
 
305
256
  let chroma = "";
306
257
  if (c <= 0.1 && c >= GRAY_THRESHOLD) {
@@ -322,17 +273,34 @@ function getColorNameFromColor(color: Color): string {
322
273
  lightness = "very light";
323
274
  }
324
275
 
325
- const name = [lightness, chroma, hue].filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
326
- if (alpha < 1) {
327
- return `${Math.round((1 - alpha) * 100)}% transparent ${name}`.trim();
276
+ if (chroma) {
277
+ chroma = getColorStringForLocale(chroma as ColorStringKey, locale);
278
+ }
279
+ if (lightness) {
280
+ lightness = getColorStringForLocale(lightness as ColorStringKey, locale);
328
281
  }
329
282
 
330
- return name;
283
+ const alpha = color.getChannelValue("alpha");
284
+ if (alpha < 1) {
285
+ const percentTransparent = new Intl.NumberFormat(locale, { style: "percent" }).format(1 - alpha);
286
+ return formatColorMessage("transparentColorName", locale, {
287
+ lightness,
288
+ chroma,
289
+ hue,
290
+ percentTransparent,
291
+ })
292
+ .replace(/\s+/g, " ")
293
+ .trim();
294
+ }
295
+
296
+ return formatColorMessage("colorName", locale, { lightness, chroma, hue })
297
+ .replace(/\s+/g, " ")
298
+ .trim();
331
299
  }
332
300
 
333
- function getHueNameFromColor(color: Color): string {
301
+ function getHueNameFromColor(color: Color, locale: string): string {
334
302
  const [l, c, h] = toOKLCH(color);
335
- const [name] = getOklchHueName(l, c, h);
303
+ const [name] = getOklchHueName(l, c, h, locale);
336
304
  return name;
337
305
  }
338
306
 
@@ -543,8 +511,8 @@ class RGBColorImpl implements Color {
543
511
  }
544
512
  }
545
513
 
546
- getChannelName(channel: ColorChannel, _locale: string): string {
547
- return CHANNEL_NAMES[channel] || channel;
514
+ getChannelName(channel: ColorChannel, locale: string): string {
515
+ return getColorStringForLocale(channel as ColorStringKey, locale);
548
516
  }
549
517
 
550
518
  getChannelFormatOptions(channel: ColorChannel): Intl.NumberFormatOptions {
@@ -576,12 +544,12 @@ class RGBColorImpl implements Color {
576
544
  return ["red", "green", "blue"];
577
545
  }
578
546
 
579
- getColorName(_locale: string): string {
580
- return getColorNameFromColor(this);
547
+ getColorName(locale: string): string {
548
+ return getColorNameFromColor(this, locale);
581
549
  }
582
550
 
583
- getHueName(_locale: string): string {
584
- return getHueNameFromColor(this);
551
+ getHueName(locale: string): string {
552
+ return getHueNameFromColor(this, locale);
585
553
  }
586
554
  }
587
555
 
@@ -595,9 +563,11 @@ class HSLColorImpl implements Color {
595
563
  private alpha: number;
596
564
 
597
565
  constructor(hue: number, saturation: number, lightness: number, alpha: number = 1) {
598
- this.hue = clamp(Math.round(hue) % 360, 0, 360);
599
- this.saturation = clamp(Math.round(saturation), 0, 100);
600
- this.lightness = clamp(Math.round(lightness), 0, 100);
566
+ // Store raw like upstream HSLColor's constructor — precision comes from the
567
+ // conversion (toFixed(_, 2)); rounding to integers here diverged from S2.
568
+ this.hue = clamp(hue % 360, 0, 360);
569
+ this.saturation = clamp(saturation, 0, 100);
570
+ this.lightness = clamp(lightness, 0, 100);
601
571
  this.alpha = clamp(toFixed(alpha, 2), 0, 1);
602
572
  }
603
573
 
@@ -711,8 +681,8 @@ class HSLColorImpl implements Color {
711
681
  }
712
682
  }
713
683
 
714
- getChannelName(channel: ColorChannel, _locale: string): string {
715
- return CHANNEL_NAMES[channel] || channel;
684
+ getChannelName(channel: ColorChannel, locale: string): string {
685
+ return getColorStringForLocale(channel as ColorStringKey, locale);
716
686
  }
717
687
 
718
688
  getChannelFormatOptions(channel: ColorChannel): Intl.NumberFormatOptions {
@@ -750,12 +720,12 @@ class HSLColorImpl implements Color {
750
720
  return ["hue", "saturation", "lightness"];
751
721
  }
752
722
 
753
- getColorName(_locale: string): string {
754
- return getColorNameFromColor(this);
723
+ getColorName(locale: string): string {
724
+ return getColorNameFromColor(this, locale);
755
725
  }
756
726
 
757
- getHueName(_locale: string): string {
758
- return getHueNameFromColor(this);
727
+ getHueName(locale: string): string {
728
+ return getHueNameFromColor(this, locale);
759
729
  }
760
730
  }
761
731
 
@@ -769,9 +739,10 @@ class HSBColorImpl implements Color {
769
739
  private alpha: number;
770
740
 
771
741
  constructor(hue: number, saturation: number, brightness: number, alpha: number = 1) {
772
- this.hue = clamp(Math.round(hue) % 360, 0, 360);
773
- this.saturation = clamp(Math.round(saturation), 0, 100);
774
- this.brightness = clamp(Math.round(brightness), 0, 100);
742
+ // Store raw like upstream HSBColor's constructor (see HSLColorImpl).
743
+ this.hue = clamp(hue % 360, 0, 360);
744
+ this.saturation = clamp(saturation, 0, 100);
745
+ this.brightness = clamp(brightness, 0, 100);
775
746
  this.alpha = clamp(toFixed(alpha, 2), 0, 1);
776
747
  }
777
748
 
@@ -884,8 +855,8 @@ class HSBColorImpl implements Color {
884
855
  }
885
856
  }
886
857
 
887
- getChannelName(channel: ColorChannel, _locale: string): string {
888
- return CHANNEL_NAMES[channel] || channel;
858
+ getChannelName(channel: ColorChannel, locale: string): string {
859
+ return getColorStringForLocale(channel as ColorStringKey, locale);
889
860
  }
890
861
 
891
862
  getChannelFormatOptions(channel: ColorChannel): Intl.NumberFormatOptions {
@@ -923,12 +894,12 @@ class HSBColorImpl implements Color {
923
894
  return ["hue", "saturation", "brightness"];
924
895
  }
925
896
 
926
- getColorName(_locale: string): string {
927
- return getColorNameFromColor(this);
897
+ getColorName(locale: string): string {
898
+ return getColorNameFromColor(this, locale);
928
899
  }
929
900
 
930
- getHueName(_locale: string): string {
931
- return getHueNameFromColor(this);
901
+ getHueName(locale: string): string {
902
+ return getHueNameFromColor(this, locale);
932
903
  }
933
904
  }
934
905