@planet-matrix/mobius-model 0.5.0 → 0.6.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 (175) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +123 -36
  3. package/dist/index.js +45 -4
  4. package/dist/index.js.map +183 -11
  5. package/oxlint.config.ts +6 -0
  6. package/package.json +16 -10
  7. package/src/abort/README.md +92 -0
  8. package/src/abort/abort-manager.ts +278 -0
  9. package/src/abort/abort-signal-listener-manager.ts +81 -0
  10. package/src/abort/index.ts +2 -0
  11. package/src/basic/README.md +69 -118
  12. package/src/basic/function.ts +81 -62
  13. package/src/basic/is.ts +152 -71
  14. package/src/basic/promise.ts +29 -8
  15. package/src/basic/string.ts +2 -33
  16. package/src/color/README.md +105 -0
  17. package/src/color/index.ts +3 -0
  18. package/src/color/internal.ts +42 -0
  19. package/src/color/rgb/analyze.ts +236 -0
  20. package/src/color/rgb/construct.ts +130 -0
  21. package/src/color/rgb/convert.ts +227 -0
  22. package/src/color/rgb/derive.ts +303 -0
  23. package/src/color/rgb/index.ts +6 -0
  24. package/src/color/rgb/internal.ts +208 -0
  25. package/src/color/rgb/parse.ts +302 -0
  26. package/src/color/rgb/serialize.ts +144 -0
  27. package/src/color/types.ts +57 -0
  28. package/src/color/xyz/analyze.ts +80 -0
  29. package/src/color/xyz/construct.ts +19 -0
  30. package/src/color/xyz/convert.ts +71 -0
  31. package/src/color/xyz/index.ts +3 -0
  32. package/src/color/xyz/internal.ts +23 -0
  33. package/src/css/README.md +93 -0
  34. package/src/css/class.ts +559 -0
  35. package/src/css/index.ts +1 -0
  36. package/src/encoding/README.md +66 -79
  37. package/src/encoding/base64.ts +13 -4
  38. package/src/environment/README.md +97 -0
  39. package/src/environment/basic.ts +26 -0
  40. package/src/environment/device.ts +311 -0
  41. package/src/environment/feature.ts +285 -0
  42. package/src/environment/geo.ts +337 -0
  43. package/src/environment/index.ts +7 -0
  44. package/src/environment/runtime.ts +400 -0
  45. package/src/environment/snapshot.ts +60 -0
  46. package/src/environment/variable.ts +239 -0
  47. package/src/event/README.md +90 -0
  48. package/src/event/class-event-proxy.ts +228 -0
  49. package/src/event/common.ts +19 -0
  50. package/src/event/event-manager.ts +203 -0
  51. package/src/event/index.ts +4 -0
  52. package/src/event/instance-event-proxy.ts +186 -0
  53. package/src/event/internal.ts +24 -0
  54. package/src/exception/README.md +96 -0
  55. package/src/exception/browser.ts +219 -0
  56. package/src/exception/index.ts +4 -0
  57. package/src/exception/nodejs.ts +169 -0
  58. package/src/exception/normalize.ts +106 -0
  59. package/src/exception/types.ts +99 -0
  60. package/src/identifier/README.md +92 -0
  61. package/src/identifier/id.ts +119 -0
  62. package/src/identifier/index.ts +2 -0
  63. package/src/identifier/uuid.ts +187 -0
  64. package/src/index.ts +16 -1
  65. package/src/log/README.md +79 -0
  66. package/src/log/index.ts +5 -0
  67. package/src/log/log-emitter.ts +72 -0
  68. package/src/log/log-record.ts +10 -0
  69. package/src/log/log-scheduler.ts +74 -0
  70. package/src/log/log-type.ts +8 -0
  71. package/src/log/logger.ts +543 -0
  72. package/src/orchestration/README.md +89 -0
  73. package/src/orchestration/coordination/barrier.ts +214 -0
  74. package/src/orchestration/coordination/count-down-latch.ts +215 -0
  75. package/src/orchestration/coordination/errors.ts +98 -0
  76. package/src/orchestration/coordination/index.ts +16 -0
  77. package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
  78. package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
  79. package/src/orchestration/coordination/keyed-lock.ts +168 -0
  80. package/src/orchestration/coordination/mutex.ts +257 -0
  81. package/src/orchestration/coordination/permit.ts +127 -0
  82. package/src/orchestration/coordination/read-write-lock.ts +444 -0
  83. package/src/orchestration/coordination/semaphore.ts +280 -0
  84. package/src/orchestration/index.ts +1 -0
  85. package/src/random/README.md +55 -86
  86. package/src/random/index.ts +1 -1
  87. package/src/random/string.ts +35 -0
  88. package/src/reactor/README.md +4 -0
  89. package/src/reactor/reactor-core/primitive.ts +9 -9
  90. package/src/reactor/reactor-core/reactive-system.ts +5 -5
  91. package/src/singleton/README.md +79 -0
  92. package/src/singleton/factory.ts +55 -0
  93. package/src/singleton/index.ts +2 -0
  94. package/src/singleton/manager.ts +204 -0
  95. package/src/storage/README.md +107 -0
  96. package/src/storage/index.ts +1 -0
  97. package/src/storage/table.ts +449 -0
  98. package/src/timer/README.md +86 -0
  99. package/src/timer/expiration/expiration-manager.ts +594 -0
  100. package/src/timer/expiration/index.ts +3 -0
  101. package/src/timer/expiration/min-heap.ts +208 -0
  102. package/src/timer/expiration/remaining-manager.ts +241 -0
  103. package/src/timer/index.ts +1 -0
  104. package/src/type/README.md +54 -307
  105. package/src/type/class.ts +2 -2
  106. package/src/type/index.ts +14 -14
  107. package/src/type/is.ts +265 -2
  108. package/src/type/object.ts +37 -0
  109. package/src/type/string.ts +7 -2
  110. package/src/type/tuple.ts +6 -6
  111. package/src/type/union.ts +16 -0
  112. package/src/web/README.md +77 -0
  113. package/src/web/capture.ts +35 -0
  114. package/src/web/clipboard.ts +97 -0
  115. package/src/web/dom.ts +117 -0
  116. package/src/web/download.ts +16 -0
  117. package/src/web/event.ts +46 -0
  118. package/src/web/index.ts +10 -0
  119. package/src/web/local-storage.ts +113 -0
  120. package/src/web/location.ts +28 -0
  121. package/src/web/permission.ts +172 -0
  122. package/src/web/script-loader.ts +432 -0
  123. package/tests/unit/abort/abort-manager.spec.ts +225 -0
  124. package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
  125. package/tests/unit/basic/array.spec.ts +1 -1
  126. package/tests/unit/basic/stream.spec.ts +1 -1
  127. package/tests/unit/basic/string.spec.ts +0 -9
  128. package/tests/unit/color/rgb/analyze.spec.ts +110 -0
  129. package/tests/unit/color/rgb/construct.spec.ts +56 -0
  130. package/tests/unit/color/rgb/convert.spec.ts +60 -0
  131. package/tests/unit/color/rgb/derive.spec.ts +103 -0
  132. package/tests/unit/color/rgb/parse.spec.ts +66 -0
  133. package/tests/unit/color/rgb/serialize.spec.ts +46 -0
  134. package/tests/unit/color/xyz/analyze.spec.ts +33 -0
  135. package/tests/unit/color/xyz/construct.spec.ts +10 -0
  136. package/tests/unit/color/xyz/convert.spec.ts +18 -0
  137. package/tests/unit/css/class.spec.ts +157 -0
  138. package/tests/unit/environment/basic.spec.ts +20 -0
  139. package/tests/unit/environment/device.spec.ts +146 -0
  140. package/tests/unit/environment/feature.spec.ts +388 -0
  141. package/tests/unit/environment/geo.spec.ts +111 -0
  142. package/tests/unit/environment/runtime.spec.ts +364 -0
  143. package/tests/unit/environment/snapshot.spec.ts +4 -0
  144. package/tests/unit/environment/variable.spec.ts +190 -0
  145. package/tests/unit/event/class-event-proxy.spec.ts +225 -0
  146. package/tests/unit/event/event-manager.spec.ts +246 -0
  147. package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
  148. package/tests/unit/exception/browser.spec.ts +213 -0
  149. package/tests/unit/exception/nodejs.spec.ts +144 -0
  150. package/tests/unit/exception/normalize.spec.ts +57 -0
  151. package/tests/unit/identifier/id.spec.ts +71 -0
  152. package/tests/unit/identifier/uuid.spec.ts +85 -0
  153. package/tests/unit/log/log-emitter.spec.ts +33 -0
  154. package/tests/unit/log/log-scheduler.spec.ts +40 -0
  155. package/tests/unit/log/log-type.spec.ts +7 -0
  156. package/tests/unit/log/logger.spec.ts +222 -0
  157. package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
  158. package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
  159. package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
  160. package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
  161. package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
  162. package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
  163. package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
  164. package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
  165. package/tests/unit/random/string.spec.ts +11 -0
  166. package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
  167. package/tests/unit/reactor/preact-signal.spec.ts +1 -2
  168. package/tests/unit/singleton/singleton.spec.ts +49 -0
  169. package/tests/unit/storage/table.spec.ts +620 -0
  170. package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
  171. package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
  172. package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
  173. package/.oxlintrc.json +0 -5
  174. package/src/random/uuid.ts +0 -103
  175. package/tests/unit/random/uuid.spec.ts +0 -37
@@ -0,0 +1,303 @@
1
+ import {
2
+ createLinearRgbColorValue,
3
+ createSrgbColorValue,
4
+ } from "./construct.ts"
5
+ import {
6
+ internalAssertColorUnit,
7
+ internalRoundColorFloat,
8
+ } from "../internal.ts"
9
+ import {
10
+ linearRgbColorValueToSrgbColorValue,
11
+ srgbColorValueToLinearRgbColorValue,
12
+ } from "./convert.ts"
13
+
14
+ import type {
15
+ LinearRgbColorValue,
16
+ SrgbColorValue,
17
+ } from "../types.ts"
18
+
19
+ const internalOpaqueBlackLinearRgbColorValue: LinearRgbColorValue = { red: 0, green: 0, blue: 0, alpha: 1 }
20
+ const internalOpaqueWhiteLinearRgbColorValue: LinearRgbColorValue = { red: 1, green: 1, blue: 1, alpha: 1 }
21
+ const internalOpaqueGrayLinearRgbColorValue: LinearRgbColorValue = { red: 0.5, green: 0.5, blue: 0.5, alpha: 1 }
22
+
23
+ const internalMixNumber = (first: number, second: number, weight: number): number => {
24
+ return internalRoundColorFloat((first * (1 - weight)) + (second * weight))
25
+ }
26
+ const internalCompositeLinearRgbChannels = (foreground: number, background: number, foregroundAlpha: number, backgroundAlpha: number, outputAlpha: number): number => {
27
+ if (outputAlpha === 0) {
28
+ return 0
29
+ }
30
+
31
+ return internalRoundColorFloat(((foreground * foregroundAlpha) + (background * backgroundAlpha * (1 - foregroundAlpha))) / outputAlpha)
32
+ }
33
+ const internalMixSrgbColorValueWithLinearReference = (color: SrgbColorValue, referenceColor: LinearRgbColorValue, amount: number): SrgbColorValue => {
34
+ internalAssertColorUnit(amount, "amount")
35
+ const normalizedColor = createSrgbColorValue(color)
36
+
37
+ return linearRgbColorValueToSrgbColorValue(mixLinearRgbColorValues(
38
+ srgbColorValueToLinearRgbColorValue(normalizedColor),
39
+ referenceColor,
40
+ amount,
41
+ ))
42
+ }
43
+
44
+ /**
45
+ * 在 Linear RGB 层混合两个颜色值。
46
+ *
47
+ * `weight` 表示第二个颜色值的占比。
48
+ *
49
+ * @example
50
+ * ```
51
+ * // Expect: { red: 0.5, green: 0, blue: 0.5, alpha: 1 }
52
+ * const example1 = mixLinearRgbColorValues(
53
+ * { red: 1, green: 0, blue: 0, alpha: 1 },
54
+ * { red: 0, green: 0, blue: 1, alpha: 1 },
55
+ * 0.5,
56
+ * )
57
+ *
58
+ * // Expect: { red: 0.75, green: 0.75, blue: 0.75, alpha: 1 }
59
+ * const example2 = mixLinearRgbColorValues(
60
+ * { red: 1, green: 1, blue: 1, alpha: 1 },
61
+ * { red: 0, green: 0, blue: 0, alpha: 1 },
62
+ * 0.25,
63
+ * )
64
+ * ```
65
+ */
66
+ export const mixLinearRgbColorValues = (first: LinearRgbColorValue, second: LinearRgbColorValue, weight = 0.5): LinearRgbColorValue => {
67
+ internalAssertColorUnit(weight, "weight")
68
+ const normalizedFirst = createLinearRgbColorValue(first)
69
+ const normalizedSecond = createLinearRgbColorValue(second)
70
+
71
+ return createLinearRgbColorValue({
72
+ red: internalMixNumber(normalizedFirst.red, normalizedSecond.red, weight),
73
+ green: internalMixNumber(normalizedFirst.green, normalizedSecond.green, weight),
74
+ blue: internalMixNumber(normalizedFirst.blue, normalizedSecond.blue, weight),
75
+ alpha: internalMixNumber(normalizedFirst.alpha, normalizedSecond.alpha, weight),
76
+ })
77
+ }
78
+
79
+ /**
80
+ * 在 sRGB 层混合两个颜色值。
81
+ *
82
+ * 该函数会沿合法路径 `sRGB -> Linear RGB -> mix -> sRGB` 计算。
83
+ *
84
+ * @example
85
+ * ```
86
+ * // Expect: { red: 188, green: 0, blue: 188, alpha: 1 }
87
+ * const example1 = mixSrgbColorValues(
88
+ * { red: 255, green: 0, blue: 0, alpha: 1 },
89
+ * { red: 0, green: 0, blue: 255, alpha: 1 },
90
+ * 0.5,
91
+ * )
92
+ *
93
+ * // Expect: { red: 255, green: 188, blue: 188, alpha: 1 }
94
+ * const example2 = mixSrgbColorValues(
95
+ * { red: 255, green: 0, blue: 0, alpha: 1 },
96
+ * { red: 255, green: 255, blue: 255, alpha: 1 },
97
+ * 0.5,
98
+ * )
99
+ * ```
100
+ */
101
+ export const mixSrgbColorValues = (first: SrgbColorValue, second: SrgbColorValue, weight = 0.5): SrgbColorValue => {
102
+ internalAssertColorUnit(weight, "weight")
103
+ const normalizedFirst = createSrgbColorValue(first)
104
+ const normalizedSecond = createSrgbColorValue(second)
105
+ const mixedLinearRgbColorValue = mixLinearRgbColorValues(
106
+ srgbColorValueToLinearRgbColorValue(normalizedFirst),
107
+ srgbColorValueToLinearRgbColorValue(normalizedSecond),
108
+ weight,
109
+ )
110
+
111
+ return linearRgbColorValueToSrgbColorValue(mixedLinearRgbColorValue)
112
+ }
113
+
114
+ /**
115
+ * 将一个 Linear RGB 前景色合成到另一个 Linear RGB 背景色之上。
116
+ *
117
+ * 该函数在支线核心计算层直接执行 alpha 合成。
118
+ *
119
+ * @example
120
+ * ```
121
+ * // Expect: { red: 0.5, green: 0.5, blue: 1, alpha: 1 }
122
+ * const example1 = compositeLinearRgbColorValueOverBackground(
123
+ * { red: 1, green: 1, blue: 1, alpha: 0.5 },
124
+ * { red: 0, green: 0, blue: 1, alpha: 1 },
125
+ * )
126
+ *
127
+ * // Expect: { red: 1, green: 0, blue: 0, alpha: 1 }
128
+ * const example2 = compositeLinearRgbColorValueOverBackground(
129
+ * { red: 1, green: 0, blue: 0, alpha: 1 },
130
+ * { red: 0, green: 0, blue: 1, alpha: 1 },
131
+ * )
132
+ * ```
133
+ */
134
+ export const compositeLinearRgbColorValueOverBackground = (foreground: LinearRgbColorValue, background: LinearRgbColorValue): LinearRgbColorValue => {
135
+ const normalizedForeground = createLinearRgbColorValue(foreground)
136
+ const normalizedBackground = createLinearRgbColorValue(background)
137
+ const outputAlpha = internalRoundColorFloat(
138
+ normalizedForeground.alpha + (normalizedBackground.alpha * (1 - normalizedForeground.alpha)),
139
+ )
140
+
141
+ return createLinearRgbColorValue({
142
+ red: internalCompositeLinearRgbChannels(
143
+ normalizedForeground.red,
144
+ normalizedBackground.red,
145
+ normalizedForeground.alpha,
146
+ normalizedBackground.alpha,
147
+ outputAlpha,
148
+ ),
149
+ green: internalCompositeLinearRgbChannels(
150
+ normalizedForeground.green,
151
+ normalizedBackground.green,
152
+ normalizedForeground.alpha,
153
+ normalizedBackground.alpha,
154
+ outputAlpha,
155
+ ),
156
+ blue: internalCompositeLinearRgbChannels(
157
+ normalizedForeground.blue,
158
+ normalizedBackground.blue,
159
+ normalizedForeground.alpha,
160
+ normalizedBackground.alpha,
161
+ outputAlpha,
162
+ ),
163
+ alpha: outputAlpha,
164
+ })
165
+ }
166
+
167
+ /**
168
+ * 将一个 sRGB 前景色沿合法路径合成到另一个 sRGB 背景色之上。
169
+ *
170
+ * 该函数会沿合法路径 `sRGB -> Linear RGB -> composite -> sRGB` 计算。
171
+ *
172
+ * @example
173
+ * ```
174
+ * // Expect: { red: 188, green: 188, blue: 255, alpha: 1 }
175
+ * const example1 = compositeSrgbColorValueOverBackground(
176
+ * { red: 255, green: 255, blue: 255, alpha: 0.5 },
177
+ * { red: 0, green: 0, blue: 255, alpha: 1 },
178
+ * )
179
+ *
180
+ * // Expect: { red: 255, green: 0, blue: 0, alpha: 1 }
181
+ * const example2 = compositeSrgbColorValueOverBackground(
182
+ * { red: 255, green: 0, blue: 0, alpha: 1 },
183
+ * { red: 0, green: 0, blue: 255, alpha: 1 },
184
+ * )
185
+ * ```
186
+ */
187
+ export const compositeSrgbColorValueOverBackground = (foreground: SrgbColorValue, background: SrgbColorValue): SrgbColorValue => {
188
+ const normalizedForeground = createSrgbColorValue(foreground)
189
+ const normalizedBackground = createSrgbColorValue(background)
190
+
191
+ return linearRgbColorValueToSrgbColorValue(compositeLinearRgbColorValueOverBackground(
192
+ srgbColorValueToLinearRgbColorValue(normalizedForeground),
193
+ srgbColorValueToLinearRgbColorValue(normalizedBackground),
194
+ ))
195
+ }
196
+
197
+ /**
198
+ * 调整一个 sRGB 颜色值的透明度。
199
+ *
200
+ * @example
201
+ * ```
202
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 0.4 }
203
+ * const example1 = fadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.4)
204
+ *
205
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 0 }
206
+ * const example2 = fadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
207
+ * ```
208
+ */
209
+ export const fadeSrgbColorValue = (color: SrgbColorValue, alpha: number): SrgbColorValue => {
210
+ internalAssertColorUnit(alpha, "alpha")
211
+ const normalizedColor = createSrgbColorValue(color)
212
+
213
+ return createSrgbColorValue({
214
+ red: normalizedColor.red,
215
+ green: normalizedColor.green,
216
+ blue: normalizedColor.blue,
217
+ alpha,
218
+ })
219
+ }
220
+
221
+ /**
222
+ * 沿合法路径将一个 sRGB 颜色值向白色方向推进。
223
+ *
224
+ * @example
225
+ * ```
226
+ * // Expect: { red: 190, green: 198, blue: 212, alpha: 1 }
227
+ * const example1 = tintSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.5)
228
+ *
229
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
230
+ * const example2 = tintSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
231
+ * ```
232
+ */
233
+ export const tintSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
234
+ return internalMixSrgbColorValueWithLinearReference(color, internalOpaqueWhiteLinearRgbColorValue, amount)
235
+ }
236
+
237
+ /**
238
+ * 沿合法路径将一个 sRGB 颜色值向黑色方向推进。
239
+ *
240
+ * @example
241
+ * ```
242
+ * // Expect: { red: 35, green: 73, blue: 111, alpha: 1 }
243
+ * const example1 = shadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.5)
244
+ *
245
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
246
+ * const example2 = shadeSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
247
+ * ```
248
+ */
249
+ export const shadeSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
250
+ return internalMixSrgbColorValueWithLinearReference(color, internalOpaqueBlackLinearRgbColorValue, amount)
251
+ }
252
+
253
+ /**
254
+ * 沿合法路径将一个 sRGB 颜色值向中性灰方向推进。
255
+ *
256
+ * @example
257
+ * ```
258
+ * // Expect: { red: 141, green: 153, blue: 171, alpha: 1 }
259
+ * const example1 = toneSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.5)
260
+ *
261
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
262
+ * const example2 = toneSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
263
+ * ```
264
+ */
265
+ export const toneSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
266
+ return internalMixSrgbColorValueWithLinearReference(color, internalOpaqueGrayLinearRgbColorValue, amount)
267
+ }
268
+
269
+ /**
270
+ * 沿合法路径提高一个 sRGB 颜色值的亮度倾向。
271
+ *
272
+ * 该能力当前等价于向白色混合。
273
+ *
274
+ * @example
275
+ * ```
276
+ * // Expect: { red: 143, green: 160, blue: 186, alpha: 1 }
277
+ * const example1 = lightenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.25)
278
+ *
279
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
280
+ * const example2 = lightenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
281
+ * ```
282
+ */
283
+ export const lightenSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
284
+ return tintSrgbColorValue(color, amount)
285
+ }
286
+
287
+ /**
288
+ * 沿合法路径降低一个 sRGB 颜色值的亮度倾向。
289
+ *
290
+ * 该能力当前等价于向黑色混合。
291
+ *
292
+ * @example
293
+ * ```
294
+ * // Expect: { red: 44, green: 89, blue: 134, alpha: 1 }
295
+ * const example1 = darkenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0.25)
296
+ *
297
+ * // Expect: { red: 51, green: 102, blue: 153, alpha: 1 }
298
+ * const example2 = darkenSrgbColorValue({ red: 51, green: 102, blue: 153, alpha: 1 }, 0)
299
+ * ```
300
+ */
301
+ export const darkenSrgbColorValue = (color: SrgbColorValue, amount: number): SrgbColorValue => {
302
+ return shadeSrgbColorValue(color, amount)
303
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./construct.ts"
2
+ export * from "./convert.ts"
3
+ export * from "./parse.ts"
4
+ export * from "./serialize.ts"
5
+ export * from "./analyze.ts"
6
+ export * from "./derive.ts"
@@ -0,0 +1,208 @@
1
+ import {
2
+ internalAssertAlpha,
3
+ internalAssertColorUnit,
4
+ internalAssertFinite,
5
+ internalRoundColorFloat,
6
+ } from "../internal.ts"
7
+
8
+ import type {
9
+ HslColorValue,
10
+ HsvColorValue,
11
+ LinearRgbColorValue,
12
+ SrgbColorValue,
13
+ } from "../types.ts"
14
+
15
+ /**
16
+ * 匹配模块支持的十六进制颜色字符串格式。
17
+ */
18
+ export const internalHexPattern: RegExp = /^#?(?:[\da-fA-F]{3}|[\da-fA-F]{4}|[\da-fA-F]{6}|[\da-fA-F]{8})$/
19
+
20
+ /**
21
+ * 断言一个 sRGB 通道值是合法的 8 位整数。
22
+ */
23
+ export const internalAssertByte = (value: number, channelName: string): void => {
24
+ if (Number.isInteger(value) === false || value < 0 || value > 255) {
25
+ throw new RangeError(`Color channel ${channelName} must be an integer between 0 and 255`)
26
+ }
27
+ }
28
+
29
+ /**
30
+ * 将色相角度规范化到 `0` 到 `360` 之间,`360` 会被折叠为 `0`。
31
+ */
32
+ export const internalNormalizeHue = (value: number): number => {
33
+ internalAssertFinite(value, "Color hue")
34
+
35
+ const normalizedValue = value % 360
36
+ if (normalizedValue < 0) {
37
+ return normalizedValue + 360
38
+ }
39
+
40
+ return normalizedValue
41
+ }
42
+
43
+ /**
44
+ * 规范化 Linear RGB 颜色值结构。
45
+ */
46
+ export const internalNormalizeLinearRgbColorValue = (color: LinearRgbColorValue): LinearRgbColorValue => {
47
+ internalAssertFinite(color.red, "Color channel red")
48
+ internalAssertFinite(color.green, "Color channel green")
49
+ internalAssertFinite(color.blue, "Color channel blue")
50
+ internalAssertAlpha(color.alpha)
51
+
52
+ return {
53
+ red: color.red,
54
+ green: color.green,
55
+ blue: color.blue,
56
+ alpha: color.alpha,
57
+ }
58
+ }
59
+
60
+ /**
61
+ * 规范化 sRGB 颜色值结构。
62
+ */
63
+ export const internalNormalizeSrgbColorValue = (color: SrgbColorValue): SrgbColorValue => {
64
+ internalAssertByte(color.red, "red")
65
+ internalAssertByte(color.green, "green")
66
+ internalAssertByte(color.blue, "blue")
67
+ internalAssertAlpha(color.alpha)
68
+
69
+ return {
70
+ red: color.red,
71
+ green: color.green,
72
+ blue: color.blue,
73
+ alpha: color.alpha,
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 规范化 HSL 颜色值结构。
79
+ */
80
+ export const internalNormalizeHslColorValue = (color: HslColorValue): HslColorValue => {
81
+ internalAssertColorUnit(color.saturation, "saturation")
82
+ internalAssertColorUnit(color.lightness, "lightness")
83
+ internalAssertAlpha(color.alpha)
84
+
85
+ return {
86
+ hue: internalNormalizeHue(color.hue),
87
+ saturation: internalRoundColorFloat(color.saturation),
88
+ lightness: internalRoundColorFloat(color.lightness),
89
+ alpha: color.alpha,
90
+ }
91
+ }
92
+
93
+ /**
94
+ * 规范化 HSV 颜色值结构。
95
+ */
96
+ export const internalNormalizeHsvColorValue = (color: HsvColorValue): HsvColorValue => {
97
+ internalAssertColorUnit(color.saturation, "saturation")
98
+ internalAssertColorUnit(color.value, "value")
99
+ internalAssertAlpha(color.alpha)
100
+
101
+ return {
102
+ hue: internalNormalizeHue(color.hue),
103
+ saturation: internalRoundColorFloat(color.saturation),
104
+ value: internalRoundColorFloat(color.value),
105
+ alpha: color.alpha,
106
+ }
107
+ }
108
+
109
+ /**
110
+ * 将短格式十六进制颜色扩展为长格式。
111
+ */
112
+ export const internalExpandShortHex = (input: string): string => {
113
+ return input.split("").map(char => `${char}${char}`).join("")
114
+ }
115
+
116
+ /**
117
+ * 将 8 位通道值格式化为两位十六进制字符串。
118
+ */
119
+ export const internalFormatHexByte = (value: number): string => {
120
+ return value.toString(16).padStart(2, "0").toUpperCase()
121
+ }
122
+
123
+ /**
124
+ * 将浮点数格式化为适合颜色字符串的紧凑小数字符串。
125
+ */
126
+ export const internalFormatAlpha = (value: number): string => {
127
+ return Number(value.toFixed(4)).toString()
128
+ }
129
+
130
+ /**
131
+ * 将 `0` 到 `1` 的单位值格式化为百分比数值字符串,不附带 `%` 符号。
132
+ */
133
+ export const internalFormatPercentUnit = (value: number): string => {
134
+ internalAssertColorUnit(value, "unit")
135
+ return Number((value * 100).toFixed(2)).toString()
136
+ }
137
+
138
+ /**
139
+ * 将 RGB 字符串通道解析为合法的 8 位通道值。
140
+ */
141
+ export const internalParseRgbChannel = (input: string, channelName: string): number => {
142
+ const value = Number(input)
143
+ internalAssertByte(value, channelName)
144
+ return value
145
+ }
146
+
147
+ /**
148
+ * 将百分比字符串解析为 `0` 到 `1` 之间的单位值。
149
+ */
150
+ export const internalParsePercentUnit = (input: string, channelName: string): number => {
151
+ if (input.endsWith("%") === false) {
152
+ throw new TypeError(`Invalid ${channelName} percentage input`)
153
+ }
154
+
155
+ return internalRoundColorFloat(Number(input.slice(0, -1)) / 100)
156
+ }
157
+
158
+ /**
159
+ * 将 8 位 sRGB 通道值转换为线性光通道值。
160
+ */
161
+ export const internalGetLinearRgbChannelBySrgbChannel = (value: number): number => {
162
+ internalAssertByte(value, "sRGB")
163
+ const normalizedValue = value / 255
164
+
165
+ if (normalizedValue <= 0.040_45) {
166
+ return internalRoundColorFloat(normalizedValue / 12.92)
167
+ }
168
+
169
+ return internalRoundColorFloat(((normalizedValue + 0.055) / 1.055) ** 2.4)
170
+ }
171
+
172
+ /**
173
+ * 将线性光通道值转换为 8 位 sRGB 通道值。
174
+ */
175
+ export const internalGetSrgbChannelByLinearRgbChannel = (value: number, channelName: string): number => {
176
+ internalAssertFinite(value, `Linear RGB channel ${channelName}`)
177
+
178
+ if (value < 0 || value > 1) {
179
+ throw new RangeError(`Linear RGB channel ${channelName} must be between 0 and 1 to convert to sRGB`)
180
+ }
181
+
182
+ if (value <= 0.003_130_8) {
183
+ return Math.round(value * 12.92 * 255)
184
+ }
185
+
186
+ return Math.round(((1.055 * (value ** (1 / 2.4))) - 0.055) * 255)
187
+ }
188
+
189
+ /**
190
+ * 根据输入字符串稳定生成一个 sRGB 颜色值。
191
+ */
192
+ export const internalGetStableSrgbColorValueByString = (input: string): SrgbColorValue => {
193
+ let codePointSum = 0
194
+
195
+ for (const char of input) {
196
+ const codePoint = char.codePointAt(0)
197
+ if (codePoint !== undefined) {
198
+ codePointSum = codePointSum + codePoint
199
+ }
200
+ }
201
+
202
+ return {
203
+ red: Math.round(Math.abs(Math.sin(codePointSum) * 255)),
204
+ green: Math.round(Math.abs(Math.sin(codePointSum + 1) * 255)),
205
+ blue: Math.round(Math.abs(Math.sin(codePointSum + 2) * 255)),
206
+ alpha: 1,
207
+ }
208
+ }