@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
@@ -0,0 +1,264 @@
1
+ import type {Key} from '../models';
2
+ import {isPlainObject} from './is';
3
+
4
+ // #region Types
5
+
6
+ export type Subscription = {
7
+ /**
8
+ * Is the subscription active?
9
+ */
10
+ get active(): boolean;
11
+
12
+ /**
13
+ * Unsubscribe from changes
14
+ */
15
+ unsubscribe(): void;
16
+ };
17
+
18
+ export type SubscriptionParameters = {
19
+ isActive?: () => boolean;
20
+ key?: Key;
21
+ property: SubscriptionProperty;
22
+ subscriptions: Subscriptions;
23
+ value: unknown;
24
+ };
25
+
26
+ export type SubscriptionProperty = {
27
+ key: string;
28
+ value: unknown;
29
+ };
30
+
31
+ type SubscriptionState = {
32
+ active: boolean;
33
+ parameters: SubscriptionParameters;
34
+ };
35
+
36
+ export type Subscriptions<Value = unknown> = {
37
+ items: SubscriptionsItems;
38
+ keys?: Set<Key>;
39
+ values: SubscriptionsValues<Value>;
40
+ };
41
+
42
+ type SubscriptionsItems = {
43
+ any: Set<Subscription>;
44
+ keyed?: Map<Key, Set<Subscription>>;
45
+ };
46
+
47
+ type SubscriptionsValues<Value = unknown> = {
48
+ from: SubscriptionsValuesItem<Value, Subscription>;
49
+ to: SubscriptionsValuesItem<Subscription, Value>;
50
+ };
51
+
52
+ type SubscriptionsValuesItem<MapKey, MapValue> = {
53
+ any: Map<MapKey, MapValue>;
54
+ keyed?: Map<Key, Map<MapKey, MapValue>>;
55
+ };
56
+
57
+ // #endregion
58
+
59
+ // #region Functions
60
+
61
+ function addSubscription(subscription: Subscription, state: SubscriptionState): void {
62
+ const {key, subscriptions, value} = state.parameters;
63
+ const {items, values} = subscriptions;
64
+
65
+ if (key == null) {
66
+ items.any.add(subscription);
67
+ values.from.any.set(value, subscription);
68
+ values.to.any.set(subscription, value);
69
+
70
+ return;
71
+ }
72
+
73
+ if (items.keyed == null || values.from.keyed == null || values.to.keyed == null) {
74
+ // TODO: fix tests or document
75
+ // istanbul ignore next
76
+ return;
77
+ }
78
+
79
+ let keyedItems = items.keyed.get(key);
80
+
81
+ if (keyedItems == null) {
82
+ keyedItems = new Set();
83
+
84
+ items.keyed.set(key, keyedItems);
85
+ }
86
+
87
+ keyedItems.add(subscription);
88
+
89
+ let keyedFrom = values.from.keyed.get(key);
90
+
91
+ if (keyedFrom == null) {
92
+ keyedFrom = new Map();
93
+
94
+ values.from.keyed.set(key, keyedFrom);
95
+ }
96
+
97
+ keyedFrom.set(value, subscription);
98
+
99
+ let keyedTo = values.to.keyed.get(key);
100
+
101
+ if (keyedTo == null) {
102
+ keyedTo = new Map();
103
+
104
+ values.to.keyed.set(key, keyedTo);
105
+ }
106
+
107
+ keyedTo.set(subscription, value);
108
+ }
109
+
110
+ export function clearSubscriptions(store: Subscriptions): void {
111
+ for (const susbcription of store.values.to.any.keys()) {
112
+ susbcription.unsubscribe();
113
+ }
114
+
115
+ if (store.values.to.keyed != null) {
116
+ for (const values of store.values.to.keyed.values()) {
117
+ for (const susbcription of values.keys()) {
118
+ susbcription.unsubscribe();
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ function getExistingSubscription(state: SubscriptionState): Subscription | undefined {
125
+ const {parameters} = state;
126
+ const {values} = parameters.subscriptions;
127
+
128
+ return parameters.key == null
129
+ ? values.from.any.get(parameters.value)
130
+ : values.from.keyed?.get(parameters.key)?.get(parameters.value);
131
+ }
132
+
133
+ export function getSubscription(parameters: SubscriptionParameters): Subscription {
134
+ const state: SubscriptionState = {
135
+ parameters,
136
+ active: true,
137
+ };
138
+
139
+ const existing = getExistingSubscription(state);
140
+
141
+ if (existing != null) {
142
+ return existing;
143
+ }
144
+
145
+ if (
146
+ parameters.subscriptions.keys != null &&
147
+ parameters.key != null &&
148
+ !parameters.subscriptions.keys.has(parameters.key)
149
+ ) {
150
+ throw new Error();
151
+ }
152
+
153
+ const instance = {
154
+ unsubscribe: () => {
155
+ removeSubscription(instance as Subscription, state);
156
+ },
157
+ };
158
+
159
+ Object.defineProperties(instance, {
160
+ [PROPERTY]: {
161
+ enumerable: false,
162
+ value: true,
163
+ },
164
+ [parameters.property.key]: {
165
+ enumerable: false,
166
+ value: parameters.property.value,
167
+ },
168
+ active: {
169
+ enumerable: true,
170
+ get: () => (parameters.isActive?.() ?? true) && state.active,
171
+ },
172
+ });
173
+
174
+ addSubscription(instance as Subscription, state);
175
+
176
+ return Object.freeze(instance) as Subscription;
177
+ }
178
+
179
+ export function getSubscriptions<Value = unknown>(keys?: Set<Key>): Subscriptions<Value> {
180
+ return {
181
+ keys,
182
+ items: {
183
+ any: new Set(),
184
+ keyed: keys == null ? undefined : new Map(),
185
+ },
186
+ values: {
187
+ from: {
188
+ any: new Map(),
189
+ keyed: keys == null ? undefined : new Map(),
190
+ },
191
+ to: {
192
+ any: new Map(),
193
+ keyed: keys == null ? undefined : new Map(),
194
+ },
195
+ },
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Is the value a subscription?
201
+ *
202
+ * @param value Value to check
203
+ * @returns `true` if the value is a subscription, otherwise `false`
204
+ */
205
+ export function isSubscription(value: unknown): value is Subscription {
206
+ return isPlainObject(value) && PROPERTY in value && value[PROPERTY] === true;
207
+ }
208
+
209
+ function removeFromStore(
210
+ items: Set<Subscription>,
211
+ values: SubscriptionsValues,
212
+ subscription: Subscription,
213
+ value: unknown,
214
+ key?: Key,
215
+ ): void {
216
+ items.delete(subscription);
217
+
218
+ if (key == null) {
219
+ values.from.any.delete(value);
220
+ values.to.any.delete(subscription);
221
+ } else {
222
+ values.from.keyed?.get(key)?.delete(value);
223
+ values.to.keyed?.get(key)?.delete(subscription);
224
+ }
225
+ }
226
+
227
+ function removeSubscription(subscription: Subscription, state: SubscriptionState): void {
228
+ if (!state.active) {
229
+ return;
230
+ }
231
+
232
+ state.active = false;
233
+
234
+ const {key, subscriptions, value} = state.parameters;
235
+ const {items, values} = subscriptions;
236
+
237
+ if (key == null) {
238
+ removeFromStore(items.any, values, subscription, value);
239
+
240
+ return;
241
+ }
242
+
243
+ const keyed = items.keyed?.get(key);
244
+
245
+ if (items.keyed == null || keyed == null) {
246
+ // TODO, fix tests or document
247
+ // istanbul ignore next
248
+ return;
249
+ }
250
+
251
+ removeFromStore(keyed, values, subscription, value, key);
252
+
253
+ if (keyed.size === 0) {
254
+ items.keyed.delete(key);
255
+ }
256
+ }
257
+
258
+ // #endregion
259
+
260
+ // #region Variables
261
+
262
+ const PROPERTY = '$subscription';
263
+
264
+ // #endregion
package/src/models.ts CHANGED
@@ -278,4 +278,9 @@ export type UnionToIntersection<Union> = (
278
278
  ? Intersection & Union
279
279
  : never;
280
280
 
281
+ /**
282
+ * A function that unsubscribes from a subscription
283
+ */
284
+ export type Unsubscriber = () => void;
285
+
281
286
  // #endregion
@@ -1,5 +1,5 @@
1
+ import {isPlainObject} from '../internal/is';
1
2
  import {getString} from '../internal/string';
2
- import {isPlainObject} from '../is';
3
3
  import type {PlainObject, RequiredKeys} from '../models';
4
4
  import {lowerCase} from './case';
5
5
  import {includes} from './match';
@@ -1,6 +1,6 @@
1
1
  import {noop} from '../function';
2
- import {isPlainObject} from '../is';
3
- import type {ArrayOrPlainObject, GenericCallback, PlainObject} from '../models';
2
+ import {isPlainObject} from '../internal/is';
3
+ import type {PlainObject} from '../models';
4
4
 
5
5
  // #region Types
6
6
 
@@ -1,4 +1,4 @@
1
- import {isNonPlainObject} from '../is';
1
+ import {isNonPlainObject} from '../internal/is';
2
2
  import type {PlainObject} from '../models';
3
3
 
4
4
  // #region Types
@@ -1,4 +1,4 @@
1
- import {isNonPlainObject} from '../is';
1
+ import {isNonPlainObject} from '../internal/is';
2
2
  import type {GenericCallback, PlainObject} from '../models';
3
3
 
4
4
  // #region Types