@oscarpalmer/atoms 0.191.0 → 0.192.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.
Files changed (44) hide show
  1. package/dist/beacon.d.mts +6 -44
  2. package/dist/beacon.mjs +20 -67
  3. package/dist/color/constants.d.mts +82 -41
  4. package/dist/color/constants.mjs +102 -63
  5. package/dist/color/instance.mjs +36 -13
  6. package/dist/color/misc/alpha.mjs +9 -10
  7. package/dist/color/misc/format.mjs +4 -4
  8. package/dist/color/misc/get.mjs +18 -18
  9. package/dist/color/misc/is.mjs +22 -21
  10. package/dist/color/misc/state.d.mts +6 -5
  11. package/dist/color/misc/state.mjs +31 -26
  12. package/dist/color/models.d.mts +78 -1
  13. package/dist/color/space/hex.mjs +12 -12
  14. package/dist/color/space/hsl.mjs +16 -16
  15. package/dist/color/space/hwb.mjs +10 -10
  16. package/dist/color/space/rgb.mjs +16 -16
  17. package/dist/herald.d.mts +2 -3
  18. package/dist/index.d.mts +117 -45
  19. package/dist/index.mjs +522 -360
  20. package/dist/internal/subscription.d.mts +52 -0
  21. package/dist/internal/subscription.mjs +127 -0
  22. package/dist/models.d.mts +5 -1
  23. package/package.json +1 -1
  24. package/src/beacon.ts +32 -117
  25. package/src/color/constants.ts +115 -78
  26. package/src/color/instance.ts +65 -12
  27. package/src/color/misc/alpha.ts +13 -21
  28. package/src/color/misc/format.ts +4 -4
  29. package/src/color/misc/get.ts +23 -40
  30. package/src/color/misc/is.ts +29 -39
  31. package/src/color/misc/state.ts +77 -41
  32. package/src/color/models.ts +94 -1
  33. package/src/color/space/hex.ts +18 -23
  34. package/src/color/space/hsl.ts +16 -24
  35. package/src/color/space/hwb.ts +10 -10
  36. package/src/color/space/rgb.ts +19 -16
  37. package/src/herald.ts +1 -3
  38. package/src/index.ts +1 -0
  39. package/src/internal/subscription.ts +264 -0
  40. package/src/models.ts +5 -0
  41. package/src/string/fuzzy.ts +1 -1
  42. package/src/value/freeze.ts +2 -2
  43. package/src/value/shake.ts +1 -1
  44. package/src/value/transform.ts +1 -1
package/dist/index.mjs CHANGED
@@ -2289,6 +2289,131 @@ const MESSAGE = "Herald requires an array of event names.";
2289
2289
  const NAME_EVENTS = "events";
2290
2290
  const NAME_HERALD = "herald";
2291
2291
  //#endregion
2292
+ //#region src/internal/subscription.ts
2293
+ function addSubscription(subscription, state) {
2294
+ const { key, subscriptions, value } = state.parameters;
2295
+ const { items, values } = subscriptions;
2296
+ if (key == null) {
2297
+ items.any.add(subscription);
2298
+ values.from.any.set(value, subscription);
2299
+ values.to.any.set(subscription, value);
2300
+ return;
2301
+ }
2302
+ if (items.keyed == null || values.from.keyed == null || values.to.keyed == null)
2303
+ // istanbul ignore next
2304
+ return;
2305
+ let keyedItems = items.keyed.get(key);
2306
+ if (keyedItems == null) {
2307
+ keyedItems = /* @__PURE__ */ new Set();
2308
+ items.keyed.set(key, keyedItems);
2309
+ }
2310
+ keyedItems.add(subscription);
2311
+ let keyedFrom = values.from.keyed.get(key);
2312
+ if (keyedFrom == null) {
2313
+ keyedFrom = /* @__PURE__ */ new Map();
2314
+ values.from.keyed.set(key, keyedFrom);
2315
+ }
2316
+ keyedFrom.set(value, subscription);
2317
+ let keyedTo = values.to.keyed.get(key);
2318
+ if (keyedTo == null) {
2319
+ keyedTo = /* @__PURE__ */ new Map();
2320
+ values.to.keyed.set(key, keyedTo);
2321
+ }
2322
+ keyedTo.set(subscription, value);
2323
+ }
2324
+ function clearSubscriptions(store) {
2325
+ for (const susbcription of store.values.to.any.keys()) susbcription.unsubscribe();
2326
+ if (store.values.to.keyed != null) for (const values of store.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
2327
+ }
2328
+ function getExistingSubscription(state) {
2329
+ const { parameters } = state;
2330
+ const { values } = parameters.subscriptions;
2331
+ return parameters.key == null ? values.from.any.get(parameters.value) : values.from.keyed?.get(parameters.key)?.get(parameters.value);
2332
+ }
2333
+ function getSubscription(parameters) {
2334
+ const state = {
2335
+ parameters,
2336
+ active: true
2337
+ };
2338
+ const existing = getExistingSubscription(state);
2339
+ if (existing != null) return existing;
2340
+ if (parameters.subscriptions.keys != null && parameters.key != null && !parameters.subscriptions.keys.has(parameters.key)) throw new Error();
2341
+ const instance = { unsubscribe: () => {
2342
+ removeSubscription(instance, state);
2343
+ } };
2344
+ Object.defineProperties(instance, {
2345
+ [PROPERTY]: {
2346
+ enumerable: false,
2347
+ value: true
2348
+ },
2349
+ [parameters.property.key]: {
2350
+ enumerable: false,
2351
+ value: parameters.property.value
2352
+ },
2353
+ active: {
2354
+ enumerable: true,
2355
+ get: () => (parameters.isActive?.() ?? true) && state.active
2356
+ }
2357
+ });
2358
+ addSubscription(instance, state);
2359
+ return Object.freeze(instance);
2360
+ }
2361
+ function getSubscriptions(keys) {
2362
+ return {
2363
+ keys,
2364
+ items: {
2365
+ any: /* @__PURE__ */ new Set(),
2366
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
2367
+ },
2368
+ values: {
2369
+ from: {
2370
+ any: /* @__PURE__ */ new Map(),
2371
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
2372
+ },
2373
+ to: {
2374
+ any: /* @__PURE__ */ new Map(),
2375
+ keyed: keys == null ? void 0 : /* @__PURE__ */ new Map()
2376
+ }
2377
+ }
2378
+ };
2379
+ }
2380
+ /**
2381
+ * Is the value a subscription?
2382
+ *
2383
+ * @param value Value to check
2384
+ * @returns `true` if the value is a subscription, otherwise `false`
2385
+ */
2386
+ function isSubscription(value) {
2387
+ return isPlainObject(value) && PROPERTY in value && value[PROPERTY] === true;
2388
+ }
2389
+ function removeFromStore(items, values, subscription, value, key) {
2390
+ items.delete(subscription);
2391
+ if (key == null) {
2392
+ values.from.any.delete(value);
2393
+ values.to.any.delete(subscription);
2394
+ } else {
2395
+ values.from.keyed?.get(key)?.delete(value);
2396
+ values.to.keyed?.get(key)?.delete(subscription);
2397
+ }
2398
+ }
2399
+ function removeSubscription(subscription, state) {
2400
+ if (!state.active) return;
2401
+ state.active = false;
2402
+ const { key, subscriptions, value } = state.parameters;
2403
+ const { items, values } = subscriptions;
2404
+ if (key == null) {
2405
+ removeFromStore(items.any, values, subscription, value);
2406
+ return;
2407
+ }
2408
+ const keyed = items.keyed?.get(key);
2409
+ if (items.keyed == null || keyed == null)
2410
+ // istanbul ignore next
2411
+ return;
2412
+ removeFromStore(keyed, values, subscription, value, key);
2413
+ if (keyed.size === 0) items.keyed.delete(key);
2414
+ }
2415
+ const PROPERTY = "$subscription";
2416
+ //#endregion
2292
2417
  //#region src/internal/value/equal.ts
2293
2418
  /**
2294
2419
  * Deregister a equality comparison handler for a specific class
@@ -2633,125 +2758,6 @@ let memoizedLowerCase;
2633
2758
  let memoizedTitleCase;
2634
2759
  let memoizedUpperCase;
2635
2760
  //#endregion
2636
- //#region src/is.ts
2637
- /**
2638
- * Is the value empty, or only containing `null` or `undefined` values?
2639
- *
2640
- * @param value Value to check
2641
- * @returns `true` if the value is considered empty, otherwise `false`
2642
- */
2643
- function isEmpty(value) {
2644
- if (value == null) return true;
2645
- if (typeof value === "string") return value.length === 0;
2646
- const values = getArray(value);
2647
- const { length } = values;
2648
- for (let index = 0; index < length; index += 1) {
2649
- const item = values[index];
2650
- if (Array.isArray(item) ? item[1] != null : item != null) return false;
2651
- }
2652
- return true;
2653
- }
2654
- /**
2655
- * Is the value not empty, or holding non-empty values?
2656
- *
2657
- * @param value Value to check
2658
- * @returns `true` if the value is not considered empty, otherwise `false`
2659
- */
2660
- function isNonEmpty(value) {
2661
- return !isEmpty(value);
2662
- }
2663
- /**
2664
- * Is the value not `undefined` or `null`?
2665
- *
2666
- * @param value Value to check
2667
- * @returns `true` if the value is not `undefined` or `null`, otherwise `false`
2668
- */
2669
- function isNonNullable(value) {
2670
- return value != null;
2671
- }
2672
- /**
2673
- * Is the value not `undefined`, `null`, or stringified as an empty _(no whitespace)_ string?
2674
- *
2675
- * @param value Value to check
2676
- * @returns `true` if the value is not `undefined`, `null`, or matches an empty string, otherwise `false`
2677
- */
2678
- function isNonNullableOrEmpty(value) {
2679
- return value != null && getString(value) !== "";
2680
- }
2681
- /**
2682
- * Is the value not `undefined`, `null`, or stringified as a whitespace-only string?
2683
- *
2684
- * @param value Value to check
2685
- * @returns `true` if the value is not `undefined`, `null`, or matches a whitespace-only string, otherwise `false`
2686
- */
2687
- function isNonNullableOrWhitespace(value) {
2688
- return value != null && !EXPRESSION_WHITESPACE.test(getString(value));
2689
- }
2690
- /**
2691
- * Is the value not a number or a number-like string?
2692
- *
2693
- * @param value Value to check
2694
- * @returns `true` if the value is not a number or a number-like string, otherwise `false`
2695
- */
2696
- function isNonNumerical(value) {
2697
- return !isNumerical(value);
2698
- }
2699
- /**
2700
- * Is the value not an object _(or function)_?
2701
- *
2702
- * @param value Value to check
2703
- * @returns `true` if the value is not an object, otherwise `false`
2704
- */
2705
- function isNonObject(value) {
2706
- return !isObject(value);
2707
- }
2708
- /**
2709
- * Is the value `undefined` or `null`?
2710
- *
2711
- * @param value Value to check
2712
- * @returns `true` if the value is `undefined` or `null`, otherwise `false`
2713
- */
2714
- function isNullable(value) {
2715
- return value == null;
2716
- }
2717
- /**
2718
- * Is the value `undefined`, `null`, or stringified as an empty _(no whitespace)_ string?
2719
- *
2720
- * @param value Value to check
2721
- * @returns `true` if the value is nullable or matches an empty string, otherwise `false`
2722
- */
2723
- function isNullableOrEmpty(value) {
2724
- return value == null || getString(value) === "";
2725
- }
2726
- /**
2727
- * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
2728
- *
2729
- * @param value Value to check
2730
- * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
2731
- */
2732
- function isNullableOrWhitespace(value) {
2733
- return value == null || EXPRESSION_WHITESPACE.test(getString(value));
2734
- }
2735
- /**
2736
- * Is the value a number or a number-like string?
2737
- *
2738
- * @param value Value to check
2739
- * @returns `true` if the value is a number or a number-like string, otherwise `false`
2740
- */
2741
- function isNumerical(value) {
2742
- return isNumber(value) || typeof value === "string" && value.trim().length > 0 && !Number.isNaN(+value);
2743
- }
2744
- /**
2745
- * Is the value an object _(or function)_?
2746
- *
2747
- * @param value Value to check
2748
- * @returns `true` if the value matches, otherwise `false`
2749
- */
2750
- function isObject(value) {
2751
- return typeof value === "object" && value !== null || typeof value === "function";
2752
- }
2753
- const EXPRESSION_WHITESPACE = /^\s*$/;
2754
- //#endregion
2755
2761
  //#region src/string/match.ts
2756
2762
  /**
2757
2763
  * Check if a string ends with a specified substring
@@ -3820,11 +3826,11 @@ function beacon(value, options) {
3820
3826
  value,
3821
3827
  active: true,
3822
3828
  observable: void 0,
3823
- observers: /* @__PURE__ */ new Map(),
3824
- options: getBeaconOptions(options)
3829
+ options: getBeaconOptions(options),
3830
+ subscriptions: getSubscriptions()
3825
3831
  };
3826
3832
  const instance = {
3827
- close: () => {
3833
+ deactivate: () => {
3828
3834
  finishBeacon(state, false);
3829
3835
  },
3830
3836
  emit: (value, finish) => {
@@ -3846,10 +3852,6 @@ function beacon(value, options) {
3846
3852
  enumerable: true,
3847
3853
  get: () => state.active
3848
3854
  },
3849
- closed: {
3850
- enumerable: true,
3851
- get: () => !state.active
3852
- },
3853
3855
  observable: {
3854
3856
  enumerable: true,
3855
3857
  get: () => {
@@ -3868,15 +3870,9 @@ function beacon(value, options) {
3868
3870
  function finishBeacon(state, emit) {
3869
3871
  if (!state.active) return;
3870
3872
  state.active = false;
3871
- const entries = [...state.observers.entries()];
3872
- const { length } = entries;
3873
- for (let index = 0; index < length; index += 1) {
3874
- const [subscription, observer] = entries[index];
3875
- if (emit) observer.complete?.();
3876
- subscription.close();
3877
- }
3878
- state.observable?.close();
3879
- state.observers.clear();
3873
+ for (const [, observer] of state.subscriptions.values.to.any) if (emit) observer.complete?.();
3874
+ clearSubscriptions(state.subscriptions);
3875
+ state.observable?.deactivate();
3880
3876
  state.observable = void 0;
3881
3877
  }
3882
3878
  function getBeaconOptions(input) {
@@ -3922,29 +3918,24 @@ function isBeaconInstance(name, value) {
3922
3918
  function isObservable(value) {
3923
3919
  return isBeaconInstance(NAME_OBSERVABLE, value);
3924
3920
  }
3925
- /**
3926
- * Is the value a subscription?
3927
- *
3928
- * @param value Value to check
3929
- * @returns `true` if the value is a subscription, otherwise `false`
3930
- */
3931
- function isSubscription(value) {
3932
- return isBeaconInstance(NAME_SUBSCRIPTION, value);
3933
- }
3934
3921
  function observe(beacon) {
3935
3922
  const state = {
3936
3923
  beacon,
3937
3924
  active: beacon.active
3938
3925
  };
3939
3926
  const instance = {
3940
- close: () => {
3927
+ deactivate: () => {
3941
3928
  state.active = false;
3942
3929
  },
3943
3930
  subscribe(first, second, third) {
3944
3931
  if (!beacon.active || !state.active) throw new Error(MESSAGE_OBSERVABLE);
3945
3932
  const observer = getObserver(first, second, third);
3946
- const subscription = subscribe(state);
3947
- beacon.observers.set(subscription, observer);
3933
+ const subscription = getSubscription({
3934
+ isActive: () => beacon.active && state.active,
3935
+ property: beaconSubscription,
3936
+ subscriptions: beacon.subscriptions,
3937
+ value: observer
3938
+ });
3948
3939
  observer.next?.(beacon.value);
3949
3940
  return subscription;
3950
3941
  }
@@ -3957,42 +3948,6 @@ function observe(beacon) {
3957
3948
  active: {
3958
3949
  enumerable: true,
3959
3950
  get: () => beacon.active && state.active
3960
- },
3961
- closed: {
3962
- enumerable: true,
3963
- get: () => !beacon.active || !state.active
3964
- }
3965
- });
3966
- return Object.freeze(instance);
3967
- }
3968
- function subscribe(observable) {
3969
- function unsubscribe() {
3970
- if (active) {
3971
- active = false;
3972
- observable.beacon.observers.delete(instance);
3973
- }
3974
- }
3975
- let active = true;
3976
- const instance = {
3977
- close: () => {
3978
- unsubscribe();
3979
- },
3980
- unsubscribe: () => {
3981
- unsubscribe();
3982
- }
3983
- };
3984
- Object.defineProperties(instance, {
3985
- [KEY_BEACON]: {
3986
- enumerable: false,
3987
- value: NAME_SUBSCRIPTION
3988
- },
3989
- active: {
3990
- enumerable: true,
3991
- get: () => observable.beacon.active && observable.active && active
3992
- },
3993
- closed: {
3994
- enumerable: true,
3995
- get: () => !observable.beacon.active || !observable.active || !active
3996
3951
  }
3997
3952
  });
3998
3953
  return Object.freeze(instance);
@@ -4003,7 +3958,7 @@ function update$1(type, state, value, finish) {
4003
3958
  if (state.options.equal(state.value, value)) return;
4004
3959
  state.value = value;
4005
3960
  }
4006
- for (const [, observer] of state.observers) observer[type]?.(value);
3961
+ for (const [, observer] of state.subscriptions.values.to.any) observer[type]?.(value);
4007
3962
  if (finish === true) finishBeacon(state, true);
4008
3963
  }
4009
3964
  const KEY_BEACON = "$beacon";
@@ -4011,58 +3966,119 @@ const MESSAGE_BEACON = "Cannot retrieve observable from a closed beacon";
4011
3966
  const MESSAGE_OBSERVABLE = "Cannot subscribe to a closed observable";
4012
3967
  const NAME_BEACON = "beacon";
4013
3968
  const NAME_OBSERVABLE = "observable";
4014
- const NAME_SUBSCRIPTION = "subscription";
4015
3969
  const TYPE_ERROR = "error";
4016
3970
  const TYPE_NEXT = "next";
4017
- const ALPHA_FULL_HEX_LONG = `ff`;
4018
- const DEFAULT_ALPHA = {
4019
- hex: ALPHA_FULL_HEX_LONG,
4020
- value: 100
3971
+ const beaconSubscription = {
3972
+ key: KEY_BEACON,
3973
+ value: "subscription"
4021
3974
  };
4022
- const DEFAULT_HSL = {
4023
- hue: 0,
4024
- saturation: 0,
4025
- lightness: 0
3975
+ //#endregion
3976
+ //#region src/color/constants.ts
3977
+ const COLOR_ALPHA = {
3978
+ fullHexShort: "f",
3979
+ fullHexLong: "ff",
3980
+ name: "alpha",
3981
+ noneHex: "00",
3982
+ noneValue: 0
4026
3983
  };
4027
- const DEFAULT_HWB = {
4028
- hue: 0,
4029
- whiteness: 0,
4030
- blackness: 100
3984
+ const COLOR_DEFAULTS = {
3985
+ alpha: {
3986
+ hex: COLOR_ALPHA.fullHexLong,
3987
+ value: 100
3988
+ },
3989
+ hexBlack: "000000",
3990
+ hexWhite: "ffffff",
3991
+ hsl: {
3992
+ hue: 0,
3993
+ saturation: 0,
3994
+ lightness: 0
3995
+ },
3996
+ hwb: {
3997
+ hue: 0,
3998
+ whiteness: 0,
3999
+ blackness: 100
4000
+ },
4001
+ rgb: {
4002
+ blue: 0,
4003
+ green: 0,
4004
+ red: 0
4005
+ }
4031
4006
  };
4032
- const DEFAULT_RGB = {
4033
- blue: 0,
4034
- green: 0,
4035
- red: 0
4007
+ const COLOR_EXPRESSION = {
4008
+ alphaHex: /^([a-f0-9]{1,2})$/i,
4009
+ hexLong: /^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?$/i,
4010
+ hexShort: /^#?([a-f0-9]{3,4})$/i,
4011
+ prefix: /^#/
4012
+ };
4013
+ const COLOR_LENGTHS = {
4014
+ hexLong: 6,
4015
+ hexShort: 3
4016
+ };
4017
+ const COLOR_KEYS = {
4018
+ hsl: [
4019
+ "hue",
4020
+ "saturation",
4021
+ "lightness"
4022
+ ],
4023
+ hsla: [],
4024
+ hwb: [
4025
+ "hue",
4026
+ "whiteness",
4027
+ "blackness"
4028
+ ],
4029
+ hwba: [],
4030
+ rgb: [
4031
+ "red",
4032
+ "green",
4033
+ "blue"
4034
+ ],
4035
+ rgba: []
4036
+ };
4037
+ COLOR_KEYS.hsla = [...COLOR_KEYS.hsl, COLOR_ALPHA.name];
4038
+ COLOR_KEYS.hwba = [...COLOR_KEYS.hwb, COLOR_ALPHA.name];
4039
+ COLOR_KEYS.rgba = [...COLOR_KEYS.rgb, COLOR_ALPHA.name];
4040
+ const COLOR_MAX = {
4041
+ degree: 360,
4042
+ hex: 255,
4043
+ percent: 100
4044
+ };
4045
+ const COLOR_PROPERTY = {
4046
+ name: "$color",
4047
+ subscription: "subscription"
4048
+ };
4049
+ const COLOR_TYPE = {
4050
+ all: void 0,
4051
+ hex: "hex",
4052
+ hexa: "hexa",
4053
+ hsl: "hsl",
4054
+ hsla: "hsla",
4055
+ hwb: "hwb",
4056
+ hwba: "hwba",
4057
+ rgb: "rgb",
4058
+ rgba: "rgba"
4059
+ };
4060
+ COLOR_TYPE.all = /* @__PURE__ */ new Set([
4061
+ COLOR_ALPHA.name,
4062
+ COLOR_TYPE.hex,
4063
+ COLOR_TYPE.hexa,
4064
+ COLOR_TYPE.hsl,
4065
+ COLOR_TYPE.hsla,
4066
+ COLOR_TYPE.hwb,
4067
+ COLOR_TYPE.hwba,
4068
+ COLOR_TYPE.rgb,
4069
+ COLOR_TYPE.rgba
4070
+ ]);
4071
+ const COLOR_SRGB = {
4072
+ luminanceBlue: .0722,
4073
+ luminanceExponent: 2.4,
4074
+ luminanceGreen: .7152,
4075
+ luminanceMinimum: .03928,
4076
+ luminanceModifier: 1.055,
4077
+ luminanceMultiplier: 12.92,
4078
+ luminanceOffset: .055,
4079
+ luminanceRed: .2126,
4080
+ luminanceThreshold: .625
4036
4081
  };
4037
- const EXPRESSION_ALPHA_HEX = /^([a-f0-9]{1,2})$/i;
4038
- const EXPRESSION_HEX_LONG = /^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?$/i;
4039
- const EXPRESSION_HEX_SHORT = /^#?([a-f0-9]{3,4})$/i;
4040
- const EXPRESSION_PREFIX = /^#/;
4041
- const HEX_BLACK = "000000";
4042
- const HEX_WHITE = "ffffff";
4043
- const KEYS_HSL = [
4044
- "hue",
4045
- "saturation",
4046
- "lightness"
4047
- ];
4048
- const KEYS_HSLA = [...KEYS_HSL, "alpha"];
4049
- const KEYS_HWB = [
4050
- "hue",
4051
- "whiteness",
4052
- "blackness"
4053
- ];
4054
- const KEYS_HWBA = [...KEYS_HWB, "alpha"];
4055
- const KEYS_RGB = [
4056
- "red",
4057
- "green",
4058
- "blue"
4059
- ];
4060
- const KEYS_RGBA = [...KEYS_RGB, "alpha"];
4061
- const PROPERTY_COLOR = "$color";
4062
- const SRGB_LUMINANCE_EXPONENT = 2.4;
4063
- const SRGB_LUMINANCE_MODIFIER = 1.055;
4064
- const SRGB_LUMINANCE_MULTIPLIER = 12.92;
4065
- const SRGB_LUMINANCE_OFFSET = .055;
4066
4082
  //#endregion
4067
4083
  //#region src/internal/math/misc.ts
4068
4084
  /**
@@ -4085,17 +4101,17 @@ function roundNumber(callback, value, decimals) {
4085
4101
  //#region src/color/misc/alpha.ts
4086
4102
  function getAlpha(value, hex) {
4087
4103
  if (typeof value === "number") return getAlphaFromValue(value);
4088
- if (typeof value !== "string" || value.toLowerCase() === ALPHA_FULL_HEX_LONG) return { ...DEFAULT_ALPHA };
4089
- if (hex && EXPRESSION_ALPHA_HEX.test(value)) return {
4104
+ if (typeof value !== "string" || value.toLowerCase() === COLOR_ALPHA.fullHexLong) return { ...COLOR_DEFAULTS.alpha };
4105
+ if (hex && COLOR_EXPRESSION.alphaHex.test(value)) return {
4090
4106
  hex: value,
4091
- value: Number.parseInt(value, 16) / 255
4107
+ value: Number.parseInt(value, 16) / COLOR_MAX.hex
4092
4108
  };
4093
4109
  return getAlphaFromValue(Number.parseFloat(value));
4094
4110
  }
4095
4111
  function getAlphaHexadecimal(value) {
4096
- if (value === 0) return "00";
4097
- if (value === 100) return ALPHA_FULL_HEX_LONG;
4098
- return round(value / 100 * 255).toString(16);
4112
+ if (value === COLOR_ALPHA.noneValue) return COLOR_ALPHA.noneHex;
4113
+ if (value === COLOR_MAX.percent) return COLOR_ALPHA.fullHexLong;
4114
+ return round(value / COLOR_MAX.percent * COLOR_MAX.hex).toString(16);
4099
4115
  }
4100
4116
  function getAlphaFromValue(value) {
4101
4117
  const alpha = getAlphaValue(value);
@@ -4105,8 +4121,8 @@ function getAlphaFromValue(value) {
4105
4121
  };
4106
4122
  }
4107
4123
  function getAlphaValue(original) {
4108
- if (Number.isNaN(original)) return 100;
4109
- return clamp(original, 0, 100);
4124
+ if (Number.isNaN(original)) return COLOR_MAX.percent;
4125
+ return clamp(original, COLOR_ALPHA.noneValue, COLOR_MAX.percent);
4110
4126
  }
4111
4127
  //#endregion
4112
4128
  //#region src/color/misc/get.ts
@@ -4114,19 +4130,19 @@ function getClampedValue(value, minimum, maximum, rounding) {
4114
4130
  return typeof value === "number" && !Number.isNaN(value) ? clamp(rounding ?? false ? round(value) : value, minimum, maximum) : minimum;
4115
4131
  }
4116
4132
  function getForegroundColor(value, hex) {
4117
- const { blue, green, red } = getColorFromState(getColorState(value), "rgb");
4133
+ const { blue, green, red } = getColorFromState(getColorState(value), COLOR_TYPE.rgb);
4118
4134
  const values = [
4119
- blue / 255,
4120
- green / 255,
4121
- red / 255
4135
+ blue / COLOR_MAX.hex,
4136
+ green / COLOR_MAX.hex,
4137
+ red / COLOR_MAX.hex
4122
4138
  ];
4123
4139
  const { length } = values;
4124
4140
  for (let index = 0; index < length; index += 1) {
4125
4141
  const color = values[index];
4126
- if (color <= .03928) values[index] /= SRGB_LUMINANCE_MULTIPLIER;
4127
- else values[index] = ((color + SRGB_LUMINANCE_OFFSET) / SRGB_LUMINANCE_MODIFIER) ** SRGB_LUMINANCE_EXPONENT;
4142
+ if (color <= COLOR_SRGB.luminanceMinimum) values[index] /= COLOR_SRGB.luminanceMultiplier;
4143
+ else values[index] = ((color + COLOR_SRGB.luminanceOffset) / COLOR_SRGB.luminanceModifier) ** COLOR_SRGB.luminanceExponent;
4128
4144
  }
4129
- const foreground = .2126 * values[2] + .7152 * values[1] + .0722 * values[0] > .625 ? HEX_BLACK : HEX_WHITE;
4145
+ const foreground = COLOR_SRGB.luminanceRed * values[2] + COLOR_SRGB.luminanceGreen * values[1] + COLOR_SRGB.luminanceBlue * values[0] > COLOR_SRGB.luminanceThreshold ? COLOR_DEFAULTS.hexBlack : COLOR_DEFAULTS.hexWhite;
4130
4146
  return hex === true ? foreground : color(foreground);
4131
4147
  }
4132
4148
  /**
@@ -4152,13 +4168,13 @@ function getHexaColor(value) {
4152
4168
  * @returns Hex color string
4153
4169
  */
4154
4170
  function getHexColor(value) {
4155
- return getColorFromState(getColorState(value), "hex");
4171
+ return getColorFromState(getColorState(value), COLOR_TYPE.hex);
4156
4172
  }
4157
4173
  function getHexValue(value) {
4158
- return getClampedValue(value, 0, 255, true);
4174
+ return getClampedValue(value, 0, COLOR_MAX.hex, true);
4159
4175
  }
4160
4176
  function getDegrees(value) {
4161
- return getClampedValue(value, 0, 360);
4177
+ return getClampedValue(value, 0, COLOR_MAX.degree);
4162
4178
  }
4163
4179
  /**
4164
4180
  * Get the _HSLA_ color from any kind of value
@@ -4172,7 +4188,7 @@ function getDegrees(value) {
4172
4188
  function getHslaColor(value) {
4173
4189
  const state = getColorState(value);
4174
4190
  return {
4175
- ...getColorFromState(state, "hsl"),
4191
+ ...getColorFromState(state, COLOR_TYPE.hsl),
4176
4192
  alpha: state.alpha.value
4177
4193
  };
4178
4194
  }
@@ -4186,7 +4202,7 @@ function getHslaColor(value) {
4186
4202
  * @returns _HWB_ color
4187
4203
  */
4188
4204
  function getHwbColor(value) {
4189
- return getColorFromState(getColorState(value), "hwb");
4205
+ return getColorFromState(getColorState(value), COLOR_TYPE.hwb);
4190
4206
  }
4191
4207
  /**
4192
4208
  * Get the _HWBA_ color from any kind of value
@@ -4200,7 +4216,7 @@ function getHwbColor(value) {
4200
4216
  function getHwbaColor(value) {
4201
4217
  const state = getColorState(value);
4202
4218
  return {
4203
- ...getColorFromState(state, "hwb"),
4219
+ ...getColorFromState(state, COLOR_TYPE.hwb),
4204
4220
  alpha: state.alpha.value
4205
4221
  };
4206
4222
  }
@@ -4214,10 +4230,10 @@ function getHwbaColor(value) {
4214
4230
  * @returns _HSL_ color
4215
4231
  */
4216
4232
  function getHslColor(value) {
4217
- return getColorFromState(getColorState(value), "hsl");
4233
+ return getColorFromState(getColorState(value), COLOR_TYPE.hsl);
4218
4234
  }
4219
4235
  function getPercentage(value) {
4220
- return getClampedValue(value, 0, 100);
4236
+ return getClampedValue(value, 0, COLOR_MAX.percent);
4221
4237
  }
4222
4238
  /**
4223
4239
  * Get the _RGBA_ color from any kind of value
@@ -4231,7 +4247,7 @@ function getPercentage(value) {
4231
4247
  function getRgbaColor(value) {
4232
4248
  const state = getColorState(value);
4233
4249
  return {
4234
- ...getColorFromState(state, "rgb"),
4250
+ ...getColorFromState(state, COLOR_TYPE.rgb),
4235
4251
  alpha: state.alpha.value
4236
4252
  };
4237
4253
  }
@@ -4245,7 +4261,7 @@ function getRgbaColor(value) {
4245
4261
  * @returns _RGB_ color
4246
4262
  */
4247
4263
  function getRgbColor(value) {
4248
- return getColorFromState(getColorState(value), "rgb");
4264
+ return getColorFromState(getColorState(value), COLOR_TYPE.rgb);
4249
4265
  }
4250
4266
  //#endregion
4251
4267
  //#region src/color/misc/is.ts
@@ -4253,10 +4269,10 @@ function hasKeys(value, keys) {
4253
4269
  return typeof value === "object" && value !== null && keys.every((key) => key in value);
4254
4270
  }
4255
4271
  function isAlpha(value) {
4256
- return typeof value === "number" && between(value, 0, 100);
4272
+ return typeof value === "number" && between(value, COLOR_ALPHA.noneValue, COLOR_MAX.percent);
4257
4273
  }
4258
4274
  function isBytey(value) {
4259
- return typeof value === "number" && between(value, 0, 255);
4275
+ return typeof value === "number" && between(value, 0, COLOR_MAX.hex);
4260
4276
  }
4261
4277
  /**
4262
4278
  * Is the value a _Color_?
@@ -4265,7 +4281,7 @@ function isBytey(value) {
4265
4281
  * @returns `true` if the value is a _Color_, otherwise `false`
4266
4282
  */
4267
4283
  function isColor(value) {
4268
- return typeof value === "object" && value !== null && "$color" in value && value["$color"] === true;
4284
+ return isPlainObject(value) && COLOR_PROPERTY.name in value && value[COLOR_PROPERTY.name] === true;
4269
4285
  }
4270
4286
  function isColorValue(obj, properties) {
4271
4287
  if (typeof obj !== "object" || obj === null) return false;
@@ -4279,7 +4295,7 @@ function isColorValue(obj, properties) {
4279
4295
  return true;
4280
4296
  }
4281
4297
  function isDegree(value) {
4282
- return typeof value === "number" && between(value, 0, 360);
4298
+ return typeof value === "number" && between(value, 0, COLOR_MAX.degree);
4283
4299
  }
4284
4300
  /**
4285
4301
  * Is the value a hex color?
@@ -4299,10 +4315,10 @@ function isDegree(value) {
4299
4315
  */
4300
4316
  function isHexColor(value, alpha) {
4301
4317
  if (typeof value !== "string") return false;
4302
- if (!(EXPRESSION_HEX_SHORT.test(value) || EXPRESSION_HEX_LONG.test(value))) return false;
4318
+ if (!(COLOR_EXPRESSION.hexShort.test(value) || COLOR_EXPRESSION.hexLong.test(value))) return false;
4303
4319
  if (alpha === false) {
4304
- const unprefixed = value.replace(EXPRESSION_PREFIX, "");
4305
- return unprefixed.length === 3 || unprefixed.length === 6;
4320
+ const unprefixed = value.replace(COLOR_EXPRESSION.prefix, "");
4321
+ return unprefixed.length === COLOR_LENGTHS.hexShort || unprefixed.length === COLOR_LENGTHS.hexLong;
4306
4322
  }
4307
4323
  return true;
4308
4324
  }
@@ -4313,7 +4329,7 @@ function isHexColor(value, alpha) {
4313
4329
  * @returns `true` if the value is an _HSLA_ color, otherwise `false`
4314
4330
  */
4315
4331
  function isHslaColor(value) {
4316
- return isColorValue(value, KEYS_HSLA);
4332
+ return isColorValue(value, COLOR_KEYS.hsla);
4317
4333
  }
4318
4334
  /**
4319
4335
  * Is the value an _HSL_ color?
@@ -4322,10 +4338,10 @@ function isHslaColor(value) {
4322
4338
  * @returns `true` if the value is an _HSL_ color, otherwise `false`
4323
4339
  */
4324
4340
  function isHslColor(value) {
4325
- return isColorValue(value, KEYS_HSLA) || isColorValue(value, KEYS_HSL);
4341
+ return isColorValue(value, COLOR_KEYS.hsla) || isColorValue(value, COLOR_KEYS.hsl);
4326
4342
  }
4327
4343
  function isHslLike(value) {
4328
- return hasKeys(value, KEYS_HSL);
4344
+ return hasKeys(value, COLOR_KEYS.hsl);
4329
4345
  }
4330
4346
  /**
4331
4347
  * Is the value an _HWBA_ color?
@@ -4334,7 +4350,7 @@ function isHslLike(value) {
4334
4350
  * @returns `true` if the value is an _HWBA_ color, otherwise `false`
4335
4351
  */
4336
4352
  function isHwbaColor(value) {
4337
- return isColorValue(value, KEYS_HWBA);
4353
+ return isColorValue(value, COLOR_KEYS.hwba);
4338
4354
  }
4339
4355
  /**
4340
4356
  * Is the value an _HWB_ color?
@@ -4343,10 +4359,10 @@ function isHwbaColor(value) {
4343
4359
  * @returns `true` if the value is an _HWB_ color, otherwise `false`
4344
4360
  */
4345
4361
  function isHwbColor(value) {
4346
- return isColorValue(value, KEYS_HWB) || isColorValue(value, KEYS_HWBA);
4362
+ return isColorValue(value, COLOR_KEYS.hwb) || isColorValue(value, COLOR_KEYS.hwba);
4347
4363
  }
4348
4364
  function isHwbLike(value) {
4349
- return hasKeys(value, KEYS_HWB);
4365
+ return hasKeys(value, COLOR_KEYS.hwb);
4350
4366
  }
4351
4367
  /**
4352
4368
  * Is the value an _RGBA_ color?
@@ -4355,7 +4371,7 @@ function isHwbLike(value) {
4355
4371
  * @returns `true` if the value is an _RGBA_ color, otherwise `false`
4356
4372
  */
4357
4373
  function isRgbaColor(value) {
4358
- return isColorValue(value, KEYS_RGBA);
4374
+ return isColorValue(value, COLOR_KEYS.rgba);
4359
4375
  }
4360
4376
  /**
4361
4377
  * Is the value an _RGB_ color?
@@ -4364,13 +4380,13 @@ function isRgbaColor(value) {
4364
4380
  * @returns `true` if the value is an _RGB_ color, otherwise `false`
4365
4381
  */
4366
4382
  function isRgbColor(value) {
4367
- return isColorValue(value, KEYS_RGBA) || isColorValue(value, KEYS_RGB);
4383
+ return isColorValue(value, COLOR_KEYS.rgba) || isColorValue(value, COLOR_KEYS.rgb);
4368
4384
  }
4369
4385
  function isRgbLike(value) {
4370
- return hasKeys(value, KEYS_RGB);
4386
+ return hasKeys(value, COLOR_KEYS.rgb);
4371
4387
  }
4372
4388
  function isPercentage(value) {
4373
- return typeof value === "number" && between(value, 0, 100);
4389
+ return typeof value === "number" && between(value, 0, COLOR_MAX.percent);
4374
4390
  }
4375
4391
  const validators = {
4376
4392
  alpha: isAlpha,
@@ -4399,7 +4415,7 @@ function convertRgbToHex(rgb, alpha) {
4399
4415
  return `${hex}${a}`;
4400
4416
  }
4401
4417
  function convertRgbToHsla(value) {
4402
- const values = getRgbValues(isRgbLike(value) ? getRgbValue(value) : { ...DEFAULT_RGB });
4418
+ const values = getRgbValues(isRgbLike(value) ? getRgbValue(value) : { ...COLOR_DEFAULTS.rgb });
4403
4419
  const { delta, max, min } = values;
4404
4420
  const lightness = (min + max) / 2;
4405
4421
  let hue = 0;
@@ -4411,13 +4427,13 @@ function convertRgbToHsla(value) {
4411
4427
  }
4412
4428
  return {
4413
4429
  hue,
4414
- saturation: saturation * 100,
4415
- lightness: lightness * 100,
4416
- alpha: getAlphaValue(value?.alpha ?? 100)
4430
+ saturation: saturation * COLOR_MAX.percent,
4431
+ lightness: lightness * COLOR_MAX.percent,
4432
+ alpha: getAlphaValue(value?.alpha ?? COLOR_MAX.percent)
4417
4433
  };
4418
4434
  }
4419
4435
  function convertRgbToHwba(value) {
4420
- const values = getRgbValues(isRgbLike(value) ? getRgbValue(value) : { ...DEFAULT_RGB });
4436
+ const values = getRgbValues(isRgbLike(value) ? getRgbValue(value) : { ...COLOR_DEFAULTS.rgb });
4421
4437
  const { delta, max, min } = values;
4422
4438
  let hue = 0;
4423
4439
  if (delta !== 0) {
@@ -4426,20 +4442,20 @@ function convertRgbToHwba(value) {
4426
4442
  }
4427
4443
  return {
4428
4444
  hue,
4429
- whiteness: min * 100,
4430
- blackness: (1 - max) * 100,
4431
- alpha: getAlphaValue(value?.alpha ?? 100)
4445
+ whiteness: min * COLOR_MAX.percent,
4446
+ blackness: (1 - max) * COLOR_MAX.percent,
4447
+ alpha: getAlphaValue(value?.alpha ?? COLOR_MAX.percent)
4432
4448
  };
4433
4449
  }
4434
4450
  function getColorFromRgb(state, type) {
4435
4451
  switch (type) {
4436
- case "hex":
4452
+ case COLOR_TYPE.hex:
4437
4453
  state.hex = rgbToHex(state.rgb);
4438
4454
  break;
4439
- case "hsl":
4455
+ case COLOR_TYPE.hsl:
4440
4456
  state.hsl = rgbToHsl(state.rgb);
4441
4457
  break;
4442
- case "hwb": state.hwb = rgbToHwb(state.rgb);
4458
+ case COLOR_TYPE.hwb: state.hwb = rgbToHwb(state.rgb);
4443
4459
  }
4444
4460
  return state[type];
4445
4461
  }
@@ -4459,9 +4475,9 @@ function getRgbValue(value) {
4459
4475
  };
4460
4476
  }
4461
4477
  function getRgbValues(rgb) {
4462
- const blue = rgb.blue / 255;
4463
- const green = rgb.green / 255;
4464
- const red = rgb.red / 255;
4478
+ const blue = rgb.blue / COLOR_MAX.hex;
4479
+ const green = rgb.green / COLOR_MAX.hex;
4480
+ const red = rgb.red / COLOR_MAX.hex;
4465
4481
  const max = Math.max(blue, green, red);
4466
4482
  const min = Math.min(blue, green, red);
4467
4483
  return {
@@ -4483,7 +4499,7 @@ function getRgbValues(rgb) {
4483
4499
  * @returns Hex color string
4484
4500
  */
4485
4501
  function rgbToHex(rgb, alpha) {
4486
- return convertRgbToHex(isRgbLike(rgb) ? getRgbValue(rgb) : { ...DEFAULT_RGB }, alpha ?? false);
4502
+ return convertRgbToHex(isRgbLike(rgb) ? getRgbValue(rgb) : { ...COLOR_DEFAULTS.rgb }, alpha ?? false);
4487
4503
  }
4488
4504
  /**
4489
4505
  * Convert an _RGB(A)_ color to an _HSL_ color
@@ -4551,12 +4567,12 @@ function rgbToHwba(rgb) {
4551
4567
  //#region src/color/space/hex.ts
4552
4568
  function convertHexToRgba(value) {
4553
4569
  const normalized = getNormalizedHex(value, true);
4554
- const pairs = EXPRESSION_HEX_LONG.exec(normalized);
4570
+ const pairs = COLOR_EXPRESSION.hexLong.exec(normalized);
4555
4571
  const values = [];
4556
4572
  const { length } = pairs;
4557
4573
  for (let index = 1; index < length; index += 1) values.push(Number.parseInt(pairs[index], 16));
4558
4574
  return {
4559
- alpha: getPercentage(values[3] / 255 * 100),
4575
+ alpha: getPercentage(values[3] / COLOR_MAX.hex * 100),
4560
4576
  blue: getHexValue(values[2]),
4561
4577
  green: getHexValue(values[1]),
4562
4578
  red: getHexValue(values[0])
@@ -4564,13 +4580,13 @@ function convertHexToRgba(value) {
4564
4580
  }
4565
4581
  function getColorFromHex(state, type) {
4566
4582
  switch (type) {
4567
- case "hsl":
4583
+ case COLOR_TYPE.hsl:
4568
4584
  state.hsl ??= hexToHsl(state.hex);
4569
4585
  break;
4570
- case "hwb":
4586
+ case COLOR_TYPE.hwb:
4571
4587
  state.hwb ??= hexToHwb(state.hex);
4572
4588
  break;
4573
- case "rgb": state.rgb ??= hexToRgb(state.hex);
4589
+ case COLOR_TYPE.rgb: state.rgb ??= hexToRgb(state.hex);
4574
4590
  }
4575
4591
  return state[type];
4576
4592
  }
@@ -4585,10 +4601,10 @@ function getColorFromHex(state, type) {
4585
4601
  */
4586
4602
  function getNormalizedHex(value, alpha) {
4587
4603
  const includeAlpha = alpha ?? false;
4588
- if (!isHexColor(value)) return `${HEX_BLACK}${includeAlpha ? ALPHA_FULL_HEX_LONG : ""}`;
4589
- const normalized = value.replace(EXPRESSION_PREFIX, "");
4590
- if (normalized.length < 6) return join(`${normalized.slice(0, 3)}${includeAlpha ? normalized[3] ?? "f" : ""}`.split("").map((character) => character.repeat(2)));
4591
- return `${normalized.slice(0, 6)}${includeAlpha ? normalized.slice(6) || ALPHA_FULL_HEX_LONG : ""}`;
4604
+ if (!isHexColor(value)) return `${COLOR_DEFAULTS.hexBlack}${includeAlpha ? COLOR_ALPHA.fullHexLong : ""}`;
4605
+ const normalized = value.replace(COLOR_EXPRESSION.prefix, "");
4606
+ if (normalized.length < COLOR_LENGTHS.hexLong) return join(`${normalized.slice(0, COLOR_LENGTHS.hexShort)}${includeAlpha ? normalized[COLOR_LENGTHS.hexShort] ?? COLOR_ALPHA.fullHexShort : ""}`.split("").map((character) => character.repeat(2)));
4607
+ return `${normalized.slice(0, COLOR_LENGTHS.hexLong)}${includeAlpha ? normalized.slice(COLOR_LENGTHS.hexLong) || COLOR_ALPHA.fullHexLong : ""}`;
4592
4608
  }
4593
4609
  /**
4594
4610
  * Convert a hex color string to a _HSL_ color
@@ -4674,27 +4690,27 @@ function hexToRgba(value) {
4674
4690
  //#endregion
4675
4691
  //#region src/color/space/hsl.ts
4676
4692
  function convertHslToHwba(input) {
4677
- let { hue, lightness, saturation } = isHslLike(input) ? getHslValue(input) : { ...DEFAULT_HSL };
4678
- lightness /= 100;
4679
- saturation /= 100;
4693
+ let { hue, lightness, saturation } = isHslLike(input) ? getHslValue(input) : { ...COLOR_DEFAULTS.hsl };
4694
+ lightness /= COLOR_MAX.percent;
4695
+ saturation /= COLOR_MAX.percent;
4680
4696
  const value = lightness + saturation * Math.min(lightness, 1 - lightness);
4681
4697
  if (value === 0) saturation = 0;
4682
4698
  else saturation = 2 * (1 - lightness / value);
4683
4699
  const blackness = 1 - value;
4684
4700
  return {
4685
4701
  hue,
4686
- whiteness: (1 - saturation) * value * 100,
4687
- blackness: blackness * 100,
4688
- alpha: getAlphaValue(input?.alpha ?? 100)
4702
+ whiteness: (1 - saturation) * value * COLOR_MAX.percent,
4703
+ blackness: blackness * COLOR_MAX.percent,
4704
+ alpha: getAlphaValue(input?.alpha ?? COLOR_MAX.percent)
4689
4705
  };
4690
4706
  }
4691
4707
  function convertHslToRgba(input) {
4692
- const hsl = isHslLike(input) ? getHslValue(input) : { ...DEFAULT_HSL };
4693
- const hue = hsl.hue % 360;
4694
- const saturation = hsl.saturation / 100;
4695
- const lightness = hsl.lightness / 100;
4708
+ const hsl = isHslLike(input) ? getHslValue(input) : { ...COLOR_DEFAULTS.hsl };
4709
+ const hue = hsl.hue % COLOR_MAX.degree;
4710
+ const saturation = hsl.saturation / COLOR_MAX.percent;
4711
+ const lightness = hsl.lightness / COLOR_MAX.percent;
4696
4712
  return {
4697
- alpha: getAlphaValue(input?.alpha ?? 100),
4713
+ alpha: getAlphaValue(input?.alpha ?? COLOR_MAX.percent),
4698
4714
  blue: getHexValue(getHexyValue(hue, lightness, saturation, 4)),
4699
4715
  green: getHexValue(getHexyValue(hue, lightness, saturation, 8)),
4700
4716
  red: getHexValue(getHexyValue(hue, lightness, saturation, 0))
@@ -4702,19 +4718,19 @@ function convertHslToRgba(input) {
4702
4718
  }
4703
4719
  function getColorFromHsl(state, type) {
4704
4720
  switch (type) {
4705
- case "hex":
4721
+ case COLOR_TYPE.hex:
4706
4722
  state.hex = hslToHex(state.hsl);
4707
4723
  break;
4708
- case "hwb":
4724
+ case COLOR_TYPE.hwb:
4709
4725
  state.hwb = hslToHwb(state.hsl);
4710
4726
  break;
4711
- case "rgb": state.rgb = hslToRgb(state.hsl);
4727
+ case COLOR_TYPE.rgb: state.rgb = hslToRgb(state.hsl);
4712
4728
  }
4713
4729
  return state[type];
4714
4730
  }
4715
4731
  function getHexyValue(hue, lightness, saturation, value) {
4716
4732
  const part = (value + hue / 30) % 12;
4717
- return (lightness - saturation * Math.min(lightness, 1 - lightness) * Math.max(-1, Math.min(part - 3, 9 - part, 1))) * 255;
4733
+ return (lightness - saturation * Math.min(lightness, 1 - lightness) * Math.max(-1, Math.min(part - 3, 9 - part, 1))) * COLOR_MAX.hex;
4718
4734
  }
4719
4735
  function getHslValue(value) {
4720
4736
  return {
@@ -4796,9 +4812,9 @@ function hslToRgba(hsl) {
4796
4812
  //#endregion
4797
4813
  //#region src/color/space/hwb.ts
4798
4814
  function convertHwbToHsl(input) {
4799
- let { blackness, hue, whiteness } = isHwbLike(input) ? getHwbValue(input) : DEFAULT_HWB;
4800
- blackness /= 100;
4801
- whiteness /= 100;
4815
+ let { blackness, hue, whiteness } = isHwbLike(input) ? getHwbValue(input) : COLOR_DEFAULTS.hwb;
4816
+ blackness /= COLOR_MAX.percent;
4817
+ whiteness /= COLOR_MAX.percent;
4802
4818
  if (blackness + whiteness > 1) {
4803
4819
  const total = blackness + whiteness;
4804
4820
  blackness /= total;
@@ -4807,20 +4823,20 @@ function convertHwbToHsl(input) {
4807
4823
  const lightness = (1 - blackness + whiteness) / 2;
4808
4824
  return {
4809
4825
  hue,
4810
- saturation: getHwbSaturation(blackness, whiteness, lightness) * 100,
4811
- lightness: lightness * 100,
4812
- alpha: getAlphaValue(input?.alpha ?? 100)
4826
+ saturation: getHwbSaturation(blackness, whiteness, lightness) * COLOR_MAX.percent,
4827
+ lightness: lightness * COLOR_MAX.percent,
4828
+ alpha: getAlphaValue(input?.alpha ?? COLOR_MAX.percent)
4813
4829
  };
4814
4830
  }
4815
4831
  function getColorFromHwb(state, type) {
4816
4832
  switch (type) {
4817
- case "hex":
4833
+ case COLOR_TYPE.hex:
4818
4834
  state.hex = hwbToHex(state.hwb);
4819
4835
  break;
4820
- case "hsl":
4836
+ case COLOR_TYPE.hsl:
4821
4837
  state.hsl = hwbToHsl(state.hwb);
4822
4838
  break;
4823
- case "rgb": state.rgb = hwbToRgb(state.hwb);
4839
+ case COLOR_TYPE.rgb: state.rgb = hwbToRgb(state.hwb);
4824
4840
  }
4825
4841
  return state[type];
4826
4842
  }
@@ -4919,15 +4935,15 @@ function getColorState(value) {
4919
4935
  alpha: getAlpha(value.alpha, false),
4920
4936
  origin: void 0
4921
4937
  };
4922
- if (KEYS_HSL.every((key) => key in value)) {
4938
+ if (COLOR_KEYS.hsl.every((key) => key in value)) {
4923
4939
  state.hsl = getHslValue(value);
4924
- state.origin = "hsl";
4925
- } else if (KEYS_HWB.every((key) => key in value)) {
4940
+ state.origin = COLOR_TYPE.hsl;
4941
+ } else if (COLOR_KEYS.hwb.every((key) => key in value)) {
4926
4942
  state.hwb = getHwbValue(value);
4927
- state.origin = "hwb";
4928
- } else if (KEYS_RGB.every((key) => key in value)) {
4943
+ state.origin = COLOR_TYPE.hwb;
4944
+ } else if (COLOR_KEYS.rgb.every((key) => key in value)) {
4929
4945
  state.rgb = getRgbValue(value);
4930
- state.origin = "rgb";
4946
+ state.origin = COLOR_TYPE.rgb;
4931
4947
  }
4932
4948
  if (state.origin != null) return state;
4933
4949
  }
@@ -4936,54 +4952,59 @@ function getColorState(value) {
4936
4952
  function getColorStateForHex(value) {
4937
4953
  const normalized = getNormalizedHex(value, true);
4938
4954
  return {
4939
- hex: normalized.slice(0, 6),
4940
- alpha: getAlpha(normalized.slice(6), true),
4941
- origin: "hex"
4955
+ hex: normalized.slice(0, COLOR_LENGTHS.hexLong),
4956
+ alpha: getAlpha(normalized.slice(COLOR_LENGTHS.hexLong), true),
4957
+ origin: COLOR_TYPE.hex
4942
4958
  };
4943
4959
  }
4944
4960
  function getDefaultColorState() {
4945
4961
  return {
4946
- alpha: getAlpha(100, false),
4947
- hex: HEX_BLACK,
4948
- hsl: { ...DEFAULT_HSL },
4949
- hwb: { ...DEFAULT_HWB },
4950
- rgb: { ...DEFAULT_RGB },
4951
- origin: "hex"
4962
+ alpha: getAlpha(COLOR_MAX.percent, false),
4963
+ hex: COLOR_DEFAULTS.hexBlack,
4964
+ hsl: { ...COLOR_DEFAULTS.hsl },
4965
+ hwb: { ...COLOR_DEFAULTS.hwb },
4966
+ rgb: { ...COLOR_DEFAULTS.rgb },
4967
+ origin: COLOR_TYPE.hex
4952
4968
  };
4953
4969
  }
4954
- function setColorValue(state, type, value, alpha) {
4970
+ function setColorValue(color, state, subscriptions, type, value, alpha) {
4955
4971
  state.hex = void 0;
4956
4972
  state.hsl = void 0;
4957
4973
  state.hwb = void 0;
4958
4974
  state.rgb = void 0;
4959
4975
  state.origin = type;
4960
4976
  state[type] = value;
4961
- if (alpha != null) state.alpha = getAlpha(alpha, type === "hex");
4977
+ if (alpha != null) state.alpha = getAlpha(alpha, type === COLOR_TYPE.hex);
4978
+ for (const type of COLOR_TYPE.all) {
4979
+ const callbacks = subscriptions.values.to.keyed?.get(type);
4980
+ if (callbacks != null) for (const callback of callbacks.values()) callback(color[type]);
4981
+ }
4982
+ for (const callback of subscriptions.values.to.any.values()) callback(color);
4962
4983
  }
4963
- function setHexColor(state, value, alpha) {
4984
+ function setHexColor(color, state, subscriptions, value, alpha) {
4964
4985
  if (!isHexColor(value) || !alpha && value === state.hex) return;
4965
4986
  const normalized = getNormalizedHex(value, true);
4966
- setColorValue(state, "hex", normalized.slice(0, 6), alpha ? normalized.slice(6) : void 0);
4987
+ setColorValue(color, state, subscriptions, COLOR_TYPE.hex, normalized.slice(0, COLOR_LENGTHS.hexLong), alpha ? normalized.slice(COLOR_LENGTHS.hexLong) : void 0);
4967
4988
  }
4968
- function setHSLColor(state, value, alpha) {
4989
+ function setHSLColor(color, state, subscriptions, value, alpha) {
4969
4990
  if (!isHslLike(value)) return;
4970
- setColorValue(state, "hsl", {
4991
+ setColorValue(color, state, subscriptions, COLOR_TYPE.hsl, {
4971
4992
  hue: getDegrees(value.hue),
4972
4993
  saturation: getPercentage(value.saturation),
4973
4994
  lightness: getPercentage(value.lightness)
4974
4995
  }, alpha ? value.alpha : void 0);
4975
4996
  }
4976
- function setHWBColor(state, value, alpha) {
4997
+ function setHWBColor(color, state, subscriptions, value, alpha) {
4977
4998
  if (!isHwbLike(value)) return;
4978
- setColorValue(state, "hwb", {
4999
+ setColorValue(color, state, subscriptions, COLOR_TYPE.hwb, {
4979
5000
  hue: getDegrees(value.hue),
4980
5001
  whiteness: getPercentage(value.whiteness),
4981
5002
  blackness: getPercentage(value.blackness)
4982
5003
  }, alpha ? value.alpha : void 0);
4983
5004
  }
4984
- function setRGBColor(state, value, alpha) {
5005
+ function setRGBColor(color, state, subscriptions, value, alpha) {
4985
5006
  if (!isRgbLike(value)) return;
4986
- setColorValue(state, "rgb", {
5007
+ setColorValue(color, state, subscriptions, COLOR_TYPE.rgb, {
4987
5008
  red: getHexValue(value.red),
4988
5009
  green: getHexValue(value.green),
4989
5010
  blue: getHexValue(value.blue)
@@ -4998,15 +5019,15 @@ const getters = {
4998
5019
  //#endregion
4999
5020
  //#region src/color/misc/format.ts
5000
5021
  function formatHslColor(state, alpha) {
5001
- const { hue, lightness, saturation } = getColorFromState(state, "hsl");
5022
+ const { hue, lightness, saturation } = getColorFromState(state, COLOR_TYPE.hsl);
5002
5023
  return `hsl(${hue}deg ${saturation}% ${lightness}%${getSuffix(state, alpha)})`;
5003
5024
  }
5004
5025
  function formatHwbColor(state, alpha) {
5005
- const { blackness, hue, whiteness } = getColorFromState(state, "hwb");
5026
+ const { blackness, hue, whiteness } = getColorFromState(state, COLOR_TYPE.hwb);
5006
5027
  return `hwb(${hue}deg ${whiteness}% ${blackness}%${getSuffix(state, alpha)})`;
5007
5028
  }
5008
5029
  function formatRgbColor(state, alpha) {
5009
- const { blue, green, red } = getColorFromState(state, "rgb");
5030
+ const { blue, green, red } = getColorFromState(state, COLOR_TYPE.rgb);
5010
5031
  return `rgb(${red} ${green} ${blue}${getSuffix(state, alpha)})`;
5011
5032
  }
5012
5033
  function getSuffix(state, alpha) {
@@ -5016,15 +5037,18 @@ function getSuffix(state, alpha) {
5016
5037
  //#region src/color/instance.ts
5017
5038
  function color(value) {
5018
5039
  const state = getColorState(value);
5040
+ const subscriptions = getSubscriptions(COLOR_TYPE.all);
5019
5041
  const instance = {
5042
+ subscribe: (first, second) => subscribeToColor(subscriptions, first, second),
5020
5043
  toHexString: (alpha) => `#${alpha === true ? instance.hexa : instance.hex}`,
5021
5044
  toHslString: (alpha) => formatHslColor(state, alpha),
5022
5045
  toHwbString: (alpha) => formatHwbColor(state, alpha),
5023
5046
  toRgbString: (alpha) => formatRgbColor(state, alpha),
5024
- toString: () => instance.toHexString()
5047
+ toString: () => instance.toHexString(),
5048
+ unsubscribe: () => clearSubscriptions(subscriptions)
5025
5049
  };
5026
5050
  Object.defineProperties(instance, {
5027
- [PROPERTY_COLOR]: {
5051
+ [COLOR_PROPERTY.name]: {
5028
5052
  enumerable: false,
5029
5053
  value: true
5030
5054
  },
@@ -5033,27 +5057,27 @@ function color(value) {
5033
5057
  get: () => state.alpha.value,
5034
5058
  set: (value) => setAlphaValue(state, value)
5035
5059
  },
5036
- hex: getProperty("hex", state, false),
5037
- hexa: getProperty("hex", state, true),
5038
- hsl: getProperty("hsl", state, false),
5039
- hsla: getProperty("hsl", state, true),
5040
- hwb: getProperty("hwb", state, false),
5041
- hwba: getProperty("hwb", state, true),
5060
+ hex: getProperty(COLOR_TYPE.hex, instance, state, subscriptions, false),
5061
+ hexa: getProperty(COLOR_TYPE.hex, instance, state, subscriptions, true),
5062
+ hsl: getProperty(COLOR_TYPE.hsl, instance, state, subscriptions, false),
5063
+ hsla: getProperty(COLOR_TYPE.hsl, instance, state, subscriptions, true),
5064
+ hwb: getProperty(COLOR_TYPE.hwb, instance, state, subscriptions, false),
5065
+ hwba: getProperty(COLOR_TYPE.hwb, instance, state, subscriptions, true),
5042
5066
  origin: {
5043
5067
  enumerable: true,
5044
5068
  get: () => state.origin
5045
5069
  },
5046
- rgb: getProperty("rgb", state, false),
5047
- rgba: getProperty("rgb", state, true)
5070
+ rgb: getProperty(COLOR_TYPE.rgb, instance, state, subscriptions, false),
5071
+ rgba: getProperty(COLOR_TYPE.rgb, instance, state, subscriptions, true)
5048
5072
  });
5049
5073
  return Object.freeze(instance);
5050
5074
  }
5051
- function getProperty(space, state, alpha) {
5075
+ function getProperty(space, color, state, subscriptions, alpha) {
5052
5076
  const setValue = setters[space];
5053
5077
  return {
5054
5078
  enumerable: true,
5055
5079
  get: () => getValue$1(space, state, alpha),
5056
- set: (value) => setValue(state, value, alpha)
5080
+ set: (value) => setValue(color, state, subscriptions, value, alpha)
5057
5081
  };
5058
5082
  }
5059
5083
  function getValue$1(space, state, alpha) {
@@ -5067,6 +5091,25 @@ function getValue$1(space, state, alpha) {
5067
5091
  function setAlphaValue(state, value) {
5068
5092
  if (typeof value === "number" && !Number.isNaN(value)) state.alpha = getAlpha(value, false);
5069
5093
  }
5094
+ function subscribeToColor(subscriptions, first, second) {
5095
+ let key;
5096
+ let value;
5097
+ if (typeof first === "string") {
5098
+ key = first;
5099
+ value = second;
5100
+ } else if (typeof first === "function") value = first;
5101
+ if (typeof value !== "function") throw new Error();
5102
+ return getSubscription({
5103
+ key,
5104
+ subscriptions,
5105
+ value,
5106
+ property: colorSubscription
5107
+ });
5108
+ }
5109
+ const colorSubscription = {
5110
+ key: COLOR_PROPERTY.name,
5111
+ value: COLOR_PROPERTY.subscription
5112
+ };
5070
5113
  const setters = {
5071
5114
  hex: setHexColor,
5072
5115
  hsl: setHSLColor,
@@ -5088,6 +5131,125 @@ function getColor(value) {
5088
5131
  return isColor(value) ? value : color(value);
5089
5132
  }
5090
5133
  //#endregion
5134
+ //#region src/is.ts
5135
+ /**
5136
+ * Is the value empty, or only containing `null` or `undefined` values?
5137
+ *
5138
+ * @param value Value to check
5139
+ * @returns `true` if the value is considered empty, otherwise `false`
5140
+ */
5141
+ function isEmpty(value) {
5142
+ if (value == null) return true;
5143
+ if (typeof value === "string") return value.length === 0;
5144
+ const values = getArray(value);
5145
+ const { length } = values;
5146
+ for (let index = 0; index < length; index += 1) {
5147
+ const item = values[index];
5148
+ if (Array.isArray(item) ? item[1] != null : item != null) return false;
5149
+ }
5150
+ return true;
5151
+ }
5152
+ /**
5153
+ * Is the value not empty, or holding non-empty values?
5154
+ *
5155
+ * @param value Value to check
5156
+ * @returns `true` if the value is not considered empty, otherwise `false`
5157
+ */
5158
+ function isNonEmpty(value) {
5159
+ return !isEmpty(value);
5160
+ }
5161
+ /**
5162
+ * Is the value not `undefined` or `null`?
5163
+ *
5164
+ * @param value Value to check
5165
+ * @returns `true` if the value is not `undefined` or `null`, otherwise `false`
5166
+ */
5167
+ function isNonNullable(value) {
5168
+ return value != null;
5169
+ }
5170
+ /**
5171
+ * Is the value not `undefined`, `null`, or stringified as an empty _(no whitespace)_ string?
5172
+ *
5173
+ * @param value Value to check
5174
+ * @returns `true` if the value is not `undefined`, `null`, or matches an empty string, otherwise `false`
5175
+ */
5176
+ function isNonNullableOrEmpty(value) {
5177
+ return value != null && getString(value) !== "";
5178
+ }
5179
+ /**
5180
+ * Is the value not `undefined`, `null`, or stringified as a whitespace-only string?
5181
+ *
5182
+ * @param value Value to check
5183
+ * @returns `true` if the value is not `undefined`, `null`, or matches a whitespace-only string, otherwise `false`
5184
+ */
5185
+ function isNonNullableOrWhitespace(value) {
5186
+ return value != null && !EXPRESSION_WHITESPACE.test(getString(value));
5187
+ }
5188
+ /**
5189
+ * Is the value not a number or a number-like string?
5190
+ *
5191
+ * @param value Value to check
5192
+ * @returns `true` if the value is not a number or a number-like string, otherwise `false`
5193
+ */
5194
+ function isNonNumerical(value) {
5195
+ return !isNumerical(value);
5196
+ }
5197
+ /**
5198
+ * Is the value not an object _(or function)_?
5199
+ *
5200
+ * @param value Value to check
5201
+ * @returns `true` if the value is not an object, otherwise `false`
5202
+ */
5203
+ function isNonObject(value) {
5204
+ return !isObject(value);
5205
+ }
5206
+ /**
5207
+ * Is the value `undefined` or `null`?
5208
+ *
5209
+ * @param value Value to check
5210
+ * @returns `true` if the value is `undefined` or `null`, otherwise `false`
5211
+ */
5212
+ function isNullable(value) {
5213
+ return value == null;
5214
+ }
5215
+ /**
5216
+ * Is the value `undefined`, `null`, or stringified as an empty _(no whitespace)_ string?
5217
+ *
5218
+ * @param value Value to check
5219
+ * @returns `true` if the value is nullable or matches an empty string, otherwise `false`
5220
+ */
5221
+ function isNullableOrEmpty(value) {
5222
+ return value == null || getString(value) === "";
5223
+ }
5224
+ /**
5225
+ * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
5226
+ *
5227
+ * @param value Value to check
5228
+ * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
5229
+ */
5230
+ function isNullableOrWhitespace(value) {
5231
+ return value == null || EXPRESSION_WHITESPACE.test(getString(value));
5232
+ }
5233
+ /**
5234
+ * Is the value a number or a number-like string?
5235
+ *
5236
+ * @param value Value to check
5237
+ * @returns `true` if the value is a number or a number-like string, otherwise `false`
5238
+ */
5239
+ function isNumerical(value) {
5240
+ return isNumber(value) || typeof value === "string" && value.trim().length > 0 && !Number.isNaN(+value);
5241
+ }
5242
+ /**
5243
+ * Is the value an object _(or function)_?
5244
+ *
5245
+ * @param value Value to check
5246
+ * @returns `true` if the value matches, otherwise `false`
5247
+ */
5248
+ function isObject(value) {
5249
+ return typeof value === "object" && value !== null || typeof value === "function";
5250
+ }
5251
+ const EXPRESSION_WHITESPACE = /^\s*$/;
5252
+ //#endregion
5091
5253
  //#region src/logger.ts
5092
5254
  function isLogger(value) {
5093
5255
  return isLoggerInstance(NAME_LOGGER, value);