@kanso-labs/react-native-kanso-ui 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +20 -0
- package/README.md +205 -2
- package/dist/button/index.d.ts +56 -0
- package/dist/button/index.js +169 -0
- package/dist/button/index.js.map +1 -0
- package/dist/button/palettes.js +47 -0
- package/dist/button/palettes.js.map +1 -0
- package/dist/chip/index.js +194 -0
- package/dist/chip/index.js.map +1 -0
- package/dist/chip/styles.js +36 -0
- package/dist/chip/styles.js.map +1 -0
- package/dist/clipboard/index.js +58 -0
- package/dist/clipboard/index.js.map +1 -0
- package/dist/components/avatar/index.d.ts +82 -0
- package/dist/components/avatar/index.js +62 -0
- package/dist/components/avatar/index.js.map +1 -0
- package/dist/components/button/index.d.ts +87 -0
- package/dist/components/button/index.js +377 -0
- package/dist/components/button/index.js.map +1 -0
- package/dist/components/card/index.d.ts +78 -0
- package/dist/components/card/index.js +315 -0
- package/dist/components/card/index.js.map +1 -0
- package/dist/components/checkbox/index.d.ts +76 -0
- package/dist/components/checkbox/index.js +360 -0
- package/dist/components/checkbox/index.js.map +1 -0
- package/dist/components/chip/index.d.ts +84 -0
- package/dist/components/chip/index.js +257 -0
- package/dist/components/chip/index.js.map +1 -0
- package/dist/components/chip-group/index.d.ts +143 -0
- package/dist/components/chip-group/index.js +669 -0
- package/dist/components/chip-group/index.js.map +1 -0
- package/dist/components/copy-field/index.d.ts +60 -0
- package/dist/components/copy-field/index.js +277 -0
- package/dist/components/copy-field/index.js.map +1 -0
- package/dist/components/currency/index.d.ts +69 -0
- package/dist/components/currency/index.js +162 -0
- package/dist/components/currency/index.js.map +1 -0
- package/dist/components/form/index.d.ts +84 -0
- package/dist/components/form/index.js +95 -0
- package/dist/components/form/index.js.map +1 -0
- package/dist/components/icon-button/index.d.ts +68 -0
- package/dist/components/icon-button/index.js +289 -0
- package/dist/components/icon-button/index.js.map +1 -0
- package/dist/components/link/index.d.ts +59 -0
- package/dist/components/link/index.js +191 -0
- package/dist/components/link/index.js.map +1 -0
- package/dist/components/number-field/index.d.ts +151 -0
- package/dist/components/number-field/index.js +832 -0
- package/dist/components/number-field/index.js.map +1 -0
- package/dist/components/product-icon/index.d.ts +70 -0
- package/dist/components/product-icon/index.js +60 -0
- package/dist/components/product-icon/index.js.map +1 -0
- package/dist/components/radio-group/index.d.ts +105 -0
- package/dist/components/radio-group/index.js +597 -0
- package/dist/components/radio-group/index.js.map +1 -0
- package/dist/components/search-field/index.d.ts +98 -0
- package/dist/components/search-field/index.js +521 -0
- package/dist/components/search-field/index.js.map +1 -0
- package/dist/components/segmented-button/index.d.ts +113 -0
- package/dist/components/segmented-button/index.js +937 -0
- package/dist/components/segmented-button/index.js.map +1 -0
- package/dist/components/separator/index.d.ts +45 -0
- package/dist/components/separator/index.js +109 -0
- package/dist/components/separator/index.js.map +1 -0
- package/dist/components/stack/index.d.ts +70 -0
- package/dist/components/stack/index.js +107 -0
- package/dist/components/stack/index.js.map +1 -0
- package/dist/components/switch/index.d.ts +76 -0
- package/dist/components/switch/index.js +591 -0
- package/dist/components/switch/index.js.map +1 -0
- package/dist/components/text/index.d.ts +44 -0
- package/dist/components/text/index.js +78 -0
- package/dist/components/text/index.js.map +1 -0
- package/dist/components/text-field/index.d.ts +146 -0
- package/dist/components/text-field/index.js +228 -0
- package/dist/components/text-field/index.js.map +1 -0
- package/dist/control/index.js +117 -0
- package/dist/control/index.js.map +1 -0
- package/dist/control/styles.js +36 -0
- package/dist/control/styles.js.map +1 -0
- package/dist/field/index.d.ts +13 -0
- package/dist/field/index.js +1007 -0
- package/dist/field/index.js.map +1 -0
- package/dist/field/styles.js +131 -0
- package/dist/field/styles.js.map +1 -0
- package/dist/form/index.d.ts +24 -0
- package/dist/form/index.js +209 -0
- package/dist/form/index.js.map +1 -0
- package/dist/glyphs/icon-style.d.ts +25 -0
- package/dist/glyphs/icon-style.js +22 -0
- package/dist/glyphs/icon-style.js.map +1 -0
- package/dist/glyphs/index.js +170 -0
- package/dist/glyphs/index.js.map +1 -0
- package/dist/glyphs/styles.js +7 -0
- package/dist/glyphs/styles.js.map +1 -0
- package/dist/hooks/useWindowSizeClass.d.ts +25 -0
- package/dist/hooks/useWindowSizeClass.js +39 -0
- package/dist/hooks/useWindowSizeClass.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +27 -0
- package/dist/mark/image.js +61 -0
- package/dist/mark/image.js.map +1 -0
- package/dist/mark/index.d.ts +9 -0
- package/dist/mark/index.js +234 -0
- package/dist/mark/index.js.map +1 -0
- package/dist/mark/initials.js +65 -0
- package/dist/mark/initials.js.map +1 -0
- package/dist/mark/styles.d.ts +1 -0
- package/dist/mark/styles.js +73 -0
- package/dist/mark/styles.js.map +1 -0
- package/dist/number/parser.js +321 -0
- package/dist/number/parser.js.map +1 -0
- package/dist/number/state.js +235 -0
- package/dist/number/state.js.map +1 -0
- package/dist/overlay/host.js +111 -0
- package/dist/overlay/host.js.map +1 -0
- package/dist/press/index.js +350 -0
- package/dist/press/index.js.map +1 -0
- package/dist/press/styles.js +31 -0
- package/dist/press/styles.js.map +1 -0
- package/dist/router/index.d.ts +28 -0
- package/dist/router/index.js +82 -0
- package/dist/router/index.js.map +1 -0
- package/dist/theme/color.js +25 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/resolve.d.ts +6 -0
- package/dist/theme/resolve.js +310 -0
- package/dist/theme/resolve.js.map +1 -0
- package/dist/theme/scope.d.ts +42 -0
- package/dist/theme/scope.js +80 -0
- package/dist/theme/scope.js.map +1 -0
- package/dist/theme/styles.js +39 -0
- package/dist/theme/styles.js.map +1 -0
- package/dist/theme-scope.d.ts +56 -0
- package/dist/theme-scope.js +127 -0
- package/dist/theme-scope.js.map +1 -0
- package/dist/tokens/defaults.d.ts +407 -0
- package/dist/tokens/defaults.js +403 -0
- package/dist/tokens/defaults.js.map +1 -0
- package/dist/typography/fonts.js +84 -0
- package/dist/typography/fonts.js.map +1 -0
- package/dist/typography/roles.d.ts +10 -0
- package/dist/typography/roles.js +82 -0
- package/dist/typography/roles.js.map +1 -0
- package/package.json +132 -4
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { NumberParser } from "./parser.js";
|
|
2
|
+
import { c } from "react/compiler-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { NumberFormatter } from "@internationalized/number";
|
|
5
|
+
//#region src/number/state.ts
|
|
6
|
+
function clamp(value, min = -Infinity, max = Infinity) {
|
|
7
|
+
return Math.min(Math.max(value, min), max);
|
|
8
|
+
}
|
|
9
|
+
function handleDecimalOperation(operator, value1, value2) {
|
|
10
|
+
let result = operator === "+" ? value1 + value2 : value1 - value2;
|
|
11
|
+
if (value1 % 1 !== 0 || value2 % 1 !== 0) {
|
|
12
|
+
const value1Decimal = value1.toString().split(".");
|
|
13
|
+
const value2Decimal = value2.toString().split(".");
|
|
14
|
+
const value1DecimalLength = value1Decimal[1]?.length ?? 0;
|
|
15
|
+
const value2DecimalLength = value2Decimal[1]?.length ?? 0;
|
|
16
|
+
const multiplier = 10 ** Math.max(value1DecimalLength, value2DecimalLength);
|
|
17
|
+
const whole1 = Math.round(value1 * multiplier);
|
|
18
|
+
const whole2 = Math.round(value2 * multiplier);
|
|
19
|
+
result = operator === "+" ? whole1 + whole2 : whole1 - whole2;
|
|
20
|
+
result /= multiplier;
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
function isEqualFormatOptions(a, b) {
|
|
25
|
+
if (a === b) return true;
|
|
26
|
+
if (a === void 0 || b === void 0) return false;
|
|
27
|
+
const bValues = new Map(Object.entries(b));
|
|
28
|
+
const aEntries = Object.entries(a);
|
|
29
|
+
return aEntries.length === bValues.size && aEntries.every(([key, value]) => bValues.has(key) && bValues.get(key) === value);
|
|
30
|
+
}
|
|
31
|
+
function roundToStepPrecision(value, step) {
|
|
32
|
+
let precision = 0;
|
|
33
|
+
const stepString = step.toString();
|
|
34
|
+
const exponent = stepString.toLowerCase().indexOf("e-");
|
|
35
|
+
if (exponent > 0) precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + exponent;
|
|
36
|
+
else {
|
|
37
|
+
const point = stepString.indexOf(".");
|
|
38
|
+
if (point >= 0) precision = stepString.length - point;
|
|
39
|
+
}
|
|
40
|
+
if (precision > 0) {
|
|
41
|
+
const pow = 10 ** precision;
|
|
42
|
+
return Math.round(value * pow) / pow;
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function snapValueToStep(value, minValue, maxValue, step) {
|
|
47
|
+
const min = Number(minValue);
|
|
48
|
+
const max = Number(maxValue);
|
|
49
|
+
const remainder = (value - (Number.isNaN(min) ? 0 : min)) % step;
|
|
50
|
+
let snapped = roundToStepPrecision(Math.abs(remainder) * 2 >= step ? value + Math.sign(remainder) * (step - Math.abs(remainder)) : value - remainder, step);
|
|
51
|
+
if (!Number.isNaN(min)) {
|
|
52
|
+
if (snapped < min) snapped = min;
|
|
53
|
+
else if (!Number.isNaN(max) && snapped > max) snapped = min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step;
|
|
54
|
+
} else if (!Number.isNaN(max) && snapped > max) snapped = Math.floor(roundToStepPrecision(max / step, step)) * step;
|
|
55
|
+
return roundToStepPrecision(snapped, step);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The state of a number field: what its input holds, the number that reads
|
|
59
|
+
* as, and stepping and committing it. Pass `value` with `onChange` to
|
|
60
|
+
* control it, or `defaultValue` to let it keep its own; `onChange` is handed
|
|
61
|
+
* the committed number, `NaN` for an empty field.
|
|
62
|
+
*/
|
|
63
|
+
function useNumberFieldState(t0) {
|
|
64
|
+
const $ = c(45);
|
|
65
|
+
const { defaultValue: t1, formatOptions, isDisabled: t2, isReadOnly: t3, locale, maxValue, minValue, onChange, step, value: givenValue } = t0;
|
|
66
|
+
const givenDefault = t1 === void 0 ? NaN : t1;
|
|
67
|
+
const isDisabled = t2 === void 0 ? false : t2;
|
|
68
|
+
const isReadOnly = t3 === void 0 ? false : t3;
|
|
69
|
+
let t4;
|
|
70
|
+
if ($[0] !== step) {
|
|
71
|
+
t4 = step === void 0 || Number.isNaN(step);
|
|
72
|
+
$[0] = step;
|
|
73
|
+
$[1] = t4;
|
|
74
|
+
} else t4 = $[1];
|
|
75
|
+
const stepless = t4;
|
|
76
|
+
let t5;
|
|
77
|
+
if ($[2] !== maxValue || $[3] !== minValue || $[4] !== step || $[5] !== stepless) {
|
|
78
|
+
t5 = (value) => stepless ? clamp(value, minValue, maxValue) : snapValueToStep(value, minValue, maxValue, step);
|
|
79
|
+
$[2] = maxValue;
|
|
80
|
+
$[3] = minValue;
|
|
81
|
+
$[4] = step;
|
|
82
|
+
$[5] = stepless;
|
|
83
|
+
$[6] = t5;
|
|
84
|
+
} else t5 = $[6];
|
|
85
|
+
const snapValue = t5;
|
|
86
|
+
const nulled = givenValue === null ? NaN : givenValue;
|
|
87
|
+
let t6;
|
|
88
|
+
if ($[7] !== nulled || $[8] !== snapValue) {
|
|
89
|
+
t6 = nulled === void 0 || Number.isNaN(nulled) ? nulled : snapValue(nulled);
|
|
90
|
+
$[7] = nulled;
|
|
91
|
+
$[8] = snapValue;
|
|
92
|
+
$[9] = t6;
|
|
93
|
+
} else t6 = $[9];
|
|
94
|
+
const value_0 = t6;
|
|
95
|
+
let t7;
|
|
96
|
+
if ($[10] !== givenDefault || $[11] !== snapValue) {
|
|
97
|
+
t7 = Number.isNaN(givenDefault) ? givenDefault : snapValue(givenDefault);
|
|
98
|
+
$[10] = givenDefault;
|
|
99
|
+
$[11] = snapValue;
|
|
100
|
+
$[12] = t7;
|
|
101
|
+
} else t7 = $[12];
|
|
102
|
+
const [own, setOwn] = useState(t7);
|
|
103
|
+
const controlled = value_0 !== void 0;
|
|
104
|
+
const numberValue = controlled ? value_0 : own;
|
|
105
|
+
let t8;
|
|
106
|
+
if ($[13] !== controlled || $[14] !== numberValue || $[15] !== onChange) {
|
|
107
|
+
t8 = (next) => {
|
|
108
|
+
if (!controlled) setOwn(next);
|
|
109
|
+
if (!Object.is(numberValue, next)) onChange?.(next);
|
|
110
|
+
};
|
|
111
|
+
$[13] = controlled;
|
|
112
|
+
$[14] = numberValue;
|
|
113
|
+
$[15] = onChange;
|
|
114
|
+
$[16] = t8;
|
|
115
|
+
} else t8 = $[16];
|
|
116
|
+
const setNumberValue = t8;
|
|
117
|
+
let t9;
|
|
118
|
+
if ($[17] !== formatOptions || $[18] !== locale || $[19] !== numberValue) {
|
|
119
|
+
t9 = () => Number.isNaN(numberValue) ? "" : new NumberFormatter(locale, formatOptions).format(numberValue);
|
|
120
|
+
$[17] = formatOptions;
|
|
121
|
+
$[18] = locale;
|
|
122
|
+
$[19] = numberValue;
|
|
123
|
+
$[20] = t9;
|
|
124
|
+
} else t9 = $[20];
|
|
125
|
+
const [inputValue, setInputValue] = useState(t9);
|
|
126
|
+
let t10;
|
|
127
|
+
if ($[21] !== formatOptions || $[22] !== locale) {
|
|
128
|
+
t10 = new NumberParser(locale, formatOptions);
|
|
129
|
+
$[21] = formatOptions;
|
|
130
|
+
$[22] = locale;
|
|
131
|
+
$[23] = t10;
|
|
132
|
+
} else t10 = $[23];
|
|
133
|
+
const parser = t10;
|
|
134
|
+
const numberingSystem = parser.getNumberingSystem(inputValue);
|
|
135
|
+
const formatter = new NumberFormatter(locale, {
|
|
136
|
+
...formatOptions,
|
|
137
|
+
numberingSystem
|
|
138
|
+
});
|
|
139
|
+
const format = (next_0) => Number.isNaN(next_0) ? "" : formatter.format(next_0);
|
|
140
|
+
const clampStep = stepless ? formatter.resolvedOptions().style === "percent" ? .01 : 1 : step;
|
|
141
|
+
const [previousValue, setPreviousValue] = useState(numberValue);
|
|
142
|
+
const [previousLocale, setPreviousLocale] = useState(locale);
|
|
143
|
+
const [previousFormat, setPreviousFormat] = useState(formatOptions);
|
|
144
|
+
if (!Object.is(numberValue, previousValue) || locale !== previousLocale || !isEqualFormatOptions(formatOptions, previousFormat)) {
|
|
145
|
+
setInputValue(format(numberValue));
|
|
146
|
+
setPreviousValue(numberValue);
|
|
147
|
+
setPreviousLocale(locale);
|
|
148
|
+
setPreviousFormat(formatOptions);
|
|
149
|
+
}
|
|
150
|
+
const parsedValue = parser.parse(inputValue);
|
|
151
|
+
const commit = () => {
|
|
152
|
+
if (inputValue.length === 0) {
|
|
153
|
+
setNumberValue(NaN);
|
|
154
|
+
setInputValue(value_0 === void 0 ? "" : format(numberValue));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (Number.isNaN(parsedValue)) {
|
|
158
|
+
setInputValue(format(numberValue));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const next_1 = parser.parse(format(snapValue(parsedValue)));
|
|
162
|
+
setNumberValue(next_1);
|
|
163
|
+
setInputValue(format(value_0 === void 0 ? next_1 : numberValue));
|
|
164
|
+
};
|
|
165
|
+
const safeNextStep = (operation, t11) => {
|
|
166
|
+
const bound = t11 === void 0 ? 0 : t11;
|
|
167
|
+
if (Number.isNaN(parsedValue)) return snapValueToStep(Number.isNaN(bound) ? 0 : bound, minValue, maxValue, clampStep);
|
|
168
|
+
const snapped = snapValueToStep(parsedValue, minValue, maxValue, clampStep);
|
|
169
|
+
if (operation === "+" && snapped > parsedValue || operation === "-" && snapped < parsedValue) return snapped;
|
|
170
|
+
return snapValueToStep(handleDecimalOperation(operation, parsedValue, clampStep), minValue, maxValue, clampStep);
|
|
171
|
+
};
|
|
172
|
+
const stepTo = (next_2) => {
|
|
173
|
+
if (next_2 === numberValue) setInputValue(format(next_2));
|
|
174
|
+
setNumberValue(next_2);
|
|
175
|
+
};
|
|
176
|
+
const editable = !isDisabled && !isReadOnly;
|
|
177
|
+
const canIncrement = editable && (Number.isNaN(parsedValue) || maxValue === void 0 || Number.isNaN(maxValue) || snapValueToStep(parsedValue, minValue, maxValue, clampStep) > parsedValue || handleDecimalOperation("+", parsedValue, clampStep) <= maxValue);
|
|
178
|
+
const canDecrement = editable && (Number.isNaN(parsedValue) || minValue === void 0 || Number.isNaN(minValue) || snapValueToStep(parsedValue, minValue, maxValue, clampStep) < parsedValue || handleDecimalOperation("-", parsedValue, clampStep) >= minValue);
|
|
179
|
+
let t12;
|
|
180
|
+
if ($[24] !== maxValue || $[25] !== safeNextStep || $[26] !== stepTo) {
|
|
181
|
+
t12 = () => {
|
|
182
|
+
stepTo(safeNextStep("-", maxValue));
|
|
183
|
+
};
|
|
184
|
+
$[24] = maxValue;
|
|
185
|
+
$[25] = safeNextStep;
|
|
186
|
+
$[26] = stepTo;
|
|
187
|
+
$[27] = t12;
|
|
188
|
+
} else t12 = $[27];
|
|
189
|
+
let t13;
|
|
190
|
+
if ($[28] !== minValue || $[29] !== safeNextStep || $[30] !== stepTo) {
|
|
191
|
+
t13 = () => {
|
|
192
|
+
stepTo(safeNextStep("+", minValue));
|
|
193
|
+
};
|
|
194
|
+
$[28] = minValue;
|
|
195
|
+
$[29] = safeNextStep;
|
|
196
|
+
$[30] = stepTo;
|
|
197
|
+
$[31] = t13;
|
|
198
|
+
} else t13 = $[31];
|
|
199
|
+
let t14;
|
|
200
|
+
if ($[32] !== maxValue || $[33] !== minValue || $[34] !== parser) {
|
|
201
|
+
t14 = (next_3) => parser.isValidPartialNumber(next_3, minValue, maxValue);
|
|
202
|
+
$[32] = maxValue;
|
|
203
|
+
$[33] = minValue;
|
|
204
|
+
$[34] = parser;
|
|
205
|
+
$[35] = t14;
|
|
206
|
+
} else t14 = $[35];
|
|
207
|
+
let t15;
|
|
208
|
+
if ($[36] !== canDecrement || $[37] !== canIncrement || $[38] !== commit || $[39] !== inputValue || $[40] !== parsedValue || $[41] !== t12 || $[42] !== t13 || $[43] !== t14) {
|
|
209
|
+
t15 = {
|
|
210
|
+
canDecrement,
|
|
211
|
+
canIncrement,
|
|
212
|
+
commit,
|
|
213
|
+
decrement: t12,
|
|
214
|
+
increment: t13,
|
|
215
|
+
inputValue,
|
|
216
|
+
numberValue: parsedValue,
|
|
217
|
+
setInputValue,
|
|
218
|
+
validate: t14
|
|
219
|
+
};
|
|
220
|
+
$[36] = canDecrement;
|
|
221
|
+
$[37] = canIncrement;
|
|
222
|
+
$[38] = commit;
|
|
223
|
+
$[39] = inputValue;
|
|
224
|
+
$[40] = parsedValue;
|
|
225
|
+
$[41] = t12;
|
|
226
|
+
$[42] = t13;
|
|
227
|
+
$[43] = t14;
|
|
228
|
+
$[44] = t15;
|
|
229
|
+
} else t15 = $[44];
|
|
230
|
+
return t15;
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
export { useNumberFieldState };
|
|
234
|
+
|
|
235
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","names":["NumberFormatOptions","NumberFormatter","useMemo","useState","NumberParser","NumberFieldState","canDecrement","canIncrement","commit","decrement","increment","inputValue","numberValue","setInputValue","value","validate","NumberFieldStateOptions","defaultValue","formatOptions","isDisabled","isReadOnly","locale","maxValue","minValue","onChange","step","clamp","min","Infinity","max","Math","handleDecimalOperation","operator","value1","value2","result","value1Decimal","toString","split","value2Decimal","value1DecimalLength","length","value2DecimalLength","multiplier","whole1","round","whole2","isEqualFormatOptions","a","b","undefined","bValues","Map","Object","entries","aEntries","size","every","key","has","get","roundToStepPrecision","precision","stepString","exponent","toLowerCase","indexOf","abs","floor","log10","point","pow","snapValueToStep","Number","remainder","isNaN","snapped","sign","useNumberFieldState","t0","$","_c","t1","t2","t3","givenValue","givenDefault","NaN","t4","stepless","t5","snapValue","nulled","t6","value_0","t7","own","setOwn","controlled","t8","next","is","setNumberValue","t9","format","t10","parser","numberingSystem","getNumberingSystem","formatter","next_0","clampStep","resolvedOptions","style","previousValue","setPreviousValue","previousLocale","setPreviousLocale","previousFormat","setPreviousFormat","parsedValue","parse","next_1","safeNextStep","operation","t11","bound","stepTo","next_2","editable","t12","t13","t14","next_3","isValidPartialNumber","t15","_c","defaultValue"],"sources":["../../src/number/state.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n *\n * Modified by Kanso Labs: ported from React Stately's useNumberFieldState and\n * the number utilities beside it, reading values through ./parser and\n * leaving form validation to the field.\n */\n\nimport type { NumberFormatOptions } from '@internationalized/number'\n\nimport { NumberFormatter } from '@internationalized/number'\nimport { useMemo, useState } from 'react'\n\nimport { NumberParser } from './parser'\n\n// The state behind NumberField: the text in its input, the number that text\n// reads as, and the steps either way. It is React Stately's\n// `useNumberFieldState`, which web's NumberField reads through React Aria,\n// so the two take a value alike: a keystroke is kept only where the text\n// could still become a number in the field's locale and format, and a\n// commit, on blur or the return key, reads the text, clamps it to the\n// range, snaps it to the step and rounds it as the format shows it, then\n// writes it back formatted. The field's validity is its `error` alone, so\n// none of React Stately's form validation comes with it.\n\ntype NumberFieldState = {\n /** Whether a decrement would lower the value, given the range and step. */\n readonly canDecrement: boolean\n /** Whether an increment would raise the value, given the range and step. */\n readonly canIncrement: boolean\n /**\n * Reads the text as a number, clamps and snaps it, reports it through\n * `onChange`, and writes it back formatted.\n */\n readonly commit: () => void\n /** Steps the value down to the step boundary below it. */\n readonly decrement: () => void\n /** Steps the value up to the step boundary above it. */\n readonly increment: () => void\n /** The text in the input, as typed until it is committed. */\n readonly inputValue: string\n /** The number the text reads as, or `NaN` while it reads as none. */\n readonly numberValue: number\n /** Sets the text in the input. */\n readonly setInputValue: (value: string) => void\n /** Whether the text could still become a number, as it is typed. */\n readonly validate: (value: string) => boolean\n}\n\ntype NumberFieldStateOptions = {\n readonly defaultValue?: number | undefined\n readonly formatOptions?: NumberFormatOptions | undefined\n readonly isDisabled?: boolean | undefined\n readonly isReadOnly?: boolean | undefined\n readonly locale: string\n readonly maxValue?: number | undefined\n readonly minValue?: number | undefined\n readonly onChange?: ((value: number) => void) | undefined\n readonly step?: number | undefined\n readonly value?: null | number | undefined\n}\n\nfunction clamp(value: number, min = -Infinity, max = Infinity) {\n return Math.min(Math.max(value, min), max)\n}\n\n// Adds or subtracts on whole numbers when either side has a fraction, so\n// 0.1 + 0.2 steps to 0.3 rather than to 0.30000000000000004.\nfunction handleDecimalOperation(\n operator: '+' | '-',\n value1: number,\n value2: number,\n) {\n let result = operator === '+' ? value1 + value2 : value1 - value2\n\n if (value1 % 1 !== 0 || value2 % 1 !== 0) {\n const value1Decimal = value1.toString().split('.')\n const value2Decimal = value2.toString().split('.')\n const value1DecimalLength = value1Decimal[1]?.length ?? 0\n const value2DecimalLength = value2Decimal[1]?.length ?? 0\n const multiplier = 10 ** Math.max(value1DecimalLength, value2DecimalLength)\n\n const whole1 = Math.round(value1 * multiplier)\n const whole2 = Math.round(value2 * multiplier)\n result = operator === '+' ? whole1 + whole2 : whole1 - whole2\n result /= multiplier\n }\n\n return result\n}\n\n// Shallow, since every value a format takes is a primitive.\nfunction isEqualFormatOptions(\n a: NumberFormatOptions | undefined,\n b: NumberFormatOptions | undefined,\n) {\n if (a === b) {\n return true\n }\n if (a === undefined || b === undefined) {\n return false\n }\n\n const bValues = new Map<string, unknown>(Object.entries(b))\n const aEntries: [string, unknown][] = Object.entries(a)\n return (\n aEntries.length === bValues.size &&\n aEntries.every(\n ([key, value]) => bValues.has(key) && bValues.get(key) === value,\n )\n )\n}\n\n// A value rounded to as many decimal places as the step has, which takes\n// the floating point error off a value a step was added to.\nfunction roundToStepPrecision(value: number, step: number) {\n let precision = 0\n const stepString = step.toString()\n const exponent = stepString.toLowerCase().indexOf('e-')\n\n if (exponent > 0) {\n precision = Math.abs(Math.floor(Math.log10(Math.abs(step)))) + exponent\n } else {\n const point = stepString.indexOf('.')\n if (point >= 0) {\n precision = stepString.length - point\n }\n }\n\n if (precision > 0) {\n const pow = 10 ** precision\n return Math.round(value * pow) / pow\n }\n\n return value\n}\n\n// The nearest value a whole number of steps from the minimum, or from zero\n// with no minimum, inside the range.\nfunction snapValueToStep(\n value: number,\n minValue: number | undefined,\n maxValue: number | undefined,\n step: number,\n) {\n const min = Number(minValue)\n const max = Number(maxValue)\n const remainder = (value - (Number.isNaN(min) ? 0 : min)) % step\n let snapped = roundToStepPrecision(\n Math.abs(remainder) * 2 >= step\n ? value + Math.sign(remainder) * (step - Math.abs(remainder))\n : value - remainder,\n step,\n )\n\n if (!Number.isNaN(min)) {\n if (snapped < min) {\n snapped = min\n } else if (!Number.isNaN(max) && snapped > max) {\n snapped =\n min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step\n }\n } else if (!Number.isNaN(max) && snapped > max) {\n snapped = Math.floor(roundToStepPrecision(max / step, step)) * step\n }\n\n return roundToStepPrecision(snapped, step)\n}\n\n/**\n * The state of a number field: what its input holds, the number that reads\n * as, and stepping and committing it. Pass `value` with `onChange` to\n * control it, or `defaultValue` to let it keep its own; `onChange` is handed\n * the committed number, `NaN` for an empty field.\n */\nfunction useNumberFieldState({\n defaultValue: givenDefault = Number.NaN,\n formatOptions,\n isDisabled = false,\n isReadOnly = false,\n locale,\n maxValue,\n minValue,\n onChange,\n step,\n value: givenValue,\n}: NumberFieldStateOptions): NumberFieldState {\n const stepless = step === undefined || Number.isNaN(step)\n const snapValue = (value: number) =>\n stepless\n ? clamp(value, minValue, maxValue)\n : snapValueToStep(value, minValue, maxValue, step)\n\n const nulled = givenValue === null ? Number.NaN : givenValue\n const value =\n nulled === undefined || Number.isNaN(nulled) ? nulled : snapValue(nulled)\n const defaultValue = Number.isNaN(givenDefault)\n ? givenDefault\n : snapValue(givenDefault)\n\n const [own, setOwn] = useState(defaultValue)\n const controlled = value !== undefined\n const numberValue = controlled ? value : own\n const setNumberValue = (next: number) => {\n if (!controlled) {\n setOwn(next)\n }\n if (!Object.is(numberValue, next)) {\n onChange?.(next)\n }\n }\n\n const [inputValue, setInputValue] = useState(() =>\n Number.isNaN(numberValue)\n ? ''\n : new NumberFormatter(locale, formatOptions).format(numberValue),\n )\n const parser = useMemo(\n () => new NumberParser(locale, formatOptions),\n [locale, formatOptions],\n )\n // The numbering system the text is in, which the value is written back\n // in: digits typed in another script than the locale's stay in it.\n const numberingSystem = parser.getNumberingSystem(inputValue)\n const formatter = new NumberFormatter(locale, {\n ...formatOptions,\n numberingSystem,\n })\n const format = (next: number) =>\n Number.isNaN(next) ? '' : formatter.format(next)\n\n // A percentage steps by a whole percent when no step is given.\n const clampStep = stepless\n ? formatter.resolvedOptions().style === 'percent'\n ? 0.01\n : 1\n : step\n\n // The text follows the value, the locale and the format whenever one of\n // them changes, so a controlled value set from outside is shown.\n const [previousValue, setPreviousValue] = useState(numberValue)\n const [previousLocale, setPreviousLocale] = useState(locale)\n const [previousFormat, setPreviousFormat] = useState(formatOptions)\n if (\n !Object.is(numberValue, previousValue) ||\n locale !== previousLocale ||\n !isEqualFormatOptions(formatOptions, previousFormat)\n ) {\n setInputValue(format(numberValue))\n setPreviousValue(numberValue)\n setPreviousLocale(locale)\n setPreviousFormat(formatOptions)\n }\n\n const parsedValue = parser.parse(inputValue)\n\n const commit = () => {\n // An empty field is empty.\n if (inputValue.length === 0) {\n setNumberValue(Number.NaN)\n setInputValue(value === undefined ? '' : format(numberValue))\n return\n }\n\n // Text that reads as no number goes back to the value.\n if (Number.isNaN(parsedValue)) {\n setInputValue(format(numberValue))\n return\n }\n\n // Clamped, snapped, and rounded as the format shows it.\n const next = parser.parse(format(snapValue(parsedValue)))\n setNumberValue(next)\n // A controlled value the call site keeps is what the text goes back to.\n setInputValue(format(value === undefined ? next : numberValue))\n }\n\n // From an empty field, the bound the step heads away from, or zero. From\n // a value, the step boundary in the step's direction: the value snapped,\n // where that moves it that way, or a step on from it.\n const safeNextStep = (operation: '+' | '-', bound = 0) => {\n if (Number.isNaN(parsedValue)) {\n return snapValueToStep(\n Number.isNaN(bound) ? 0 : bound,\n minValue,\n maxValue,\n clampStep,\n )\n }\n\n const snapped = snapValueToStep(parsedValue, minValue, maxValue, clampStep)\n if (\n (operation === '+' && snapped > parsedValue) ||\n (operation === '-' && snapped < parsedValue)\n ) {\n return snapped\n }\n\n return snapValueToStep(\n handleDecimalOperation(operation, parsedValue, clampStep),\n minValue,\n maxValue,\n clampStep,\n )\n }\n\n const stepTo = (next: number) => {\n // Stepping to the value the field already holds changes no state, so\n // the text, which may have been edited since, is written back here.\n if (next === numberValue) {\n setInputValue(format(next))\n }\n setNumberValue(next)\n }\n\n const editable = !isDisabled && !isReadOnly\n const canIncrement =\n editable &&\n (Number.isNaN(parsedValue) ||\n maxValue === undefined ||\n Number.isNaN(maxValue) ||\n snapValueToStep(parsedValue, minValue, maxValue, clampStep) >\n parsedValue ||\n handleDecimalOperation('+', parsedValue, clampStep) <= maxValue)\n const canDecrement =\n editable &&\n (Number.isNaN(parsedValue) ||\n minValue === undefined ||\n Number.isNaN(minValue) ||\n snapValueToStep(parsedValue, minValue, maxValue, clampStep) <\n parsedValue ||\n handleDecimalOperation('-', parsedValue, clampStep) >= minValue)\n\n return {\n canDecrement,\n canIncrement,\n commit,\n decrement: () => {\n stepTo(safeNextStep('-', maxValue))\n },\n increment: () => {\n stepTo(safeNextStep('+', minValue))\n },\n inputValue,\n numberValue: parsedValue,\n setInputValue,\n validate: (next) => parser.isValidPartialNumber(next, minValue, maxValue),\n }\n}\n\nexport { useNumberFieldState }\nexport type { NumberFieldState, NumberFieldStateOptions }\n"],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
|
+
import { createContext, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/overlay/host.tsx
|
|
6
|
+
const OverlayHostContext = createContext(null);
|
|
7
|
+
const styles = StyleSheet.create({ fill: {
|
|
8
|
+
bottom: 0,
|
|
9
|
+
left: 0,
|
|
10
|
+
pointerEvents: "box-none",
|
|
11
|
+
position: "absolute",
|
|
12
|
+
right: 0,
|
|
13
|
+
top: 0
|
|
14
|
+
} });
|
|
15
|
+
/**
|
|
16
|
+
* Hosts the overlays drawn inside it: its children, then a layer over them
|
|
17
|
+
* that fills the view around the host. Mounting or unmounting an overlay
|
|
18
|
+
* renders the layer alone, so the screen under it keeps its state.
|
|
19
|
+
*
|
|
20
|
+
* The outermost `ThemeScope` renders one, so an app has one at its root.
|
|
21
|
+
*/
|
|
22
|
+
function OverlayHost(t0) {
|
|
23
|
+
const $ = c(6);
|
|
24
|
+
const { children } = t0;
|
|
25
|
+
const [store] = useState(storeFor);
|
|
26
|
+
let t1;
|
|
27
|
+
if ($[0] !== store) {
|
|
28
|
+
t1 = /* @__PURE__ */ jsx(OverlayLayer, {
|
|
29
|
+
attach: store.attach,
|
|
30
|
+
store
|
|
31
|
+
});
|
|
32
|
+
$[0] = store;
|
|
33
|
+
$[1] = t1;
|
|
34
|
+
} else t1 = $[1];
|
|
35
|
+
let t2;
|
|
36
|
+
if ($[2] !== children || $[3] !== store || $[4] !== t1) {
|
|
37
|
+
t2 = /* @__PURE__ */ jsxs(OverlayHostContext, {
|
|
38
|
+
value: store,
|
|
39
|
+
children: [children, t1]
|
|
40
|
+
});
|
|
41
|
+
$[2] = children;
|
|
42
|
+
$[3] = store;
|
|
43
|
+
$[4] = t1;
|
|
44
|
+
$[5] = t2;
|
|
45
|
+
} else t2 = $[5];
|
|
46
|
+
return t2;
|
|
47
|
+
}
|
|
48
|
+
function OverlayLayer(t0) {
|
|
49
|
+
const $ = c(5);
|
|
50
|
+
const { attach, store } = t0;
|
|
51
|
+
const entries = useSyncExternalStore(store.subscribe, store.entries);
|
|
52
|
+
let t1;
|
|
53
|
+
if ($[0] !== entries) {
|
|
54
|
+
t1 = entries.map(_temp);
|
|
55
|
+
$[0] = entries;
|
|
56
|
+
$[1] = t1;
|
|
57
|
+
} else t1 = $[1];
|
|
58
|
+
let t2;
|
|
59
|
+
if ($[2] !== attach || $[3] !== t1) {
|
|
60
|
+
t2 = /* @__PURE__ */ jsx(View, {
|
|
61
|
+
ref: attach,
|
|
62
|
+
style: styles.fill,
|
|
63
|
+
children: t1
|
|
64
|
+
});
|
|
65
|
+
$[2] = attach;
|
|
66
|
+
$[3] = t1;
|
|
67
|
+
$[4] = t2;
|
|
68
|
+
} else t2 = $[4];
|
|
69
|
+
return t2;
|
|
70
|
+
}
|
|
71
|
+
function _temp(t0) {
|
|
72
|
+
const [key, content] = t0;
|
|
73
|
+
return /* @__PURE__ */ jsx(View, {
|
|
74
|
+
style: styles.fill,
|
|
75
|
+
children: content
|
|
76
|
+
}, key);
|
|
77
|
+
}
|
|
78
|
+
function storeFor() {
|
|
79
|
+
const content = /* @__PURE__ */ new Map();
|
|
80
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
81
|
+
let entries = [];
|
|
82
|
+
let layer = null;
|
|
83
|
+
const changed = () => {
|
|
84
|
+
entries = [...content];
|
|
85
|
+
for (const listener of listeners) listener();
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
attach: (view) => {
|
|
89
|
+
layer = view;
|
|
90
|
+
},
|
|
91
|
+
entries: () => entries,
|
|
92
|
+
layer: () => layer,
|
|
93
|
+
remove: (key) => {
|
|
94
|
+
if (content.delete(key)) changed();
|
|
95
|
+
},
|
|
96
|
+
set: (key, node) => {
|
|
97
|
+
content.set(key, node);
|
|
98
|
+
changed();
|
|
99
|
+
},
|
|
100
|
+
subscribe: (listener) => {
|
|
101
|
+
listeners.add(listener);
|
|
102
|
+
return () => {
|
|
103
|
+
listeners.delete(listener);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { OverlayHost, OverlayHostContext };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","names":["ReactNode","createContext","use","useId","useLayoutEffect","useState","useSyncExternalStore","StyleSheet","View","ScopeContext","useScope","Entry","key","content","OverlayStore","attach","layer","entries","remove","set","subscribe","listener","OverlayHostContext","styles","create","fill","bottom","left","pointerEvents","position","right","top","Overlay","t0","$","_c","children","store","scope","Error","t1","t2","t3","t4","OverlayHost","storeFor","OverlayLayer","map","_temp","Map","listeners","Set","changed","view","delete","node","add","_c"],"sources":["../../src/overlay/host.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\nimport {\n createContext,\n use,\n useId,\n useLayoutEffect,\n useState,\n useSyncExternalStore,\n} from 'react'\nimport { StyleSheet, View } from 'react-native'\n\nimport { ScopeContext, useScope } from '../theme/scope'\n\ntype Entry = readonly [key: string, content: ReactNode]\n\n/** What an overlay reaches its host through. */\ntype OverlayStore = {\n /** Takes the layer the host draws its overlays in, as its ref. */\n readonly attach: (layer: null | View) => void\n readonly entries: () => readonly Entry[]\n /** The layer the host draws its overlays in, for placing one in it. */\n readonly layer: () => null | View\n readonly remove: (key: string) => void\n readonly set: (key: string, content: ReactNode) => void\n readonly subscribe: (listener: () => void) => () => void\n}\n\nconst OverlayHostContext = createContext<null | OverlayStore>(null)\n\nconst styles = StyleSheet.create({\n // Each overlay fills the layer on a box of its own, so one laid out in the\n // flow, as a bar along an edge is, is laid out against the screen rather\n // than after the overlay before it.\n fill: {\n bottom: 0,\n left: 0,\n pointerEvents: 'box-none',\n position: 'absolute',\n right: 0,\n top: 0,\n },\n})\n\n/**\n * Draws its content above the screen, in the overlay host of the app's\n * outermost `ThemeScope`, for as long as it is mounted. A later overlay draws\n * above an earlier one.\n *\n * The content reads the `ThemeScope` around the `Overlay`, as anything else\n * there would. Other context set between the host and the `Overlay` does not\n * reach it: an overlay is a surface of its own, as web's `OverlayScope` makes\n * one, so it starts from what is around the app rather than from what is\n * around the control that opened it.\n */\nfunction Overlay({ children }: { readonly children?: ReactNode }) {\n const store = use(OverlayHostContext)\n const scope = useScope()\n const key = useId()\n\n if (store === null) {\n throw new Error(\n 'An overlay draws in the host of the outermost ThemeScope, and there is no ThemeScope around this one. Wrap the app in a ThemeScope.',\n )\n }\n\n // Set before paint, so an overlay opening never draws a frame without it,\n // and replaced in place on an update, so it keeps its place in the stack.\n useLayoutEffect(() => {\n store.set(key, <ScopeContext value={scope}>{children}</ScopeContext>)\n }, [children, key, scope, store])\n\n useLayoutEffect(\n () => () => {\n store.remove(key)\n },\n [key, store],\n )\n\n return null\n}\n\n/**\n * Hosts the overlays drawn inside it: its children, then a layer over them\n * that fills the view around the host. Mounting or unmounting an overlay\n * renders the layer alone, so the screen under it keeps its state.\n *\n * The outermost `ThemeScope` renders one, so an app has one at its root.\n */\nfunction OverlayHost({ children }: { readonly children?: ReactNode }) {\n const [store] = useState(storeFor)\n\n return (\n <OverlayHostContext value={store}>\n {children}\n <OverlayLayer attach={store.attach} store={store} />\n </OverlayHostContext>\n )\n}\n\n// The layer passes a touch through to the screen wherever no overlay is\n// drawn, so an open overlay leaves the screen around it usable. It takes its\n// ref apart from the store, since the compiler reads an object a ref is taken\n// from as a ref itself, and the store is read during render.\nfunction OverlayLayer({\n attach,\n store,\n}: {\n readonly attach: OverlayStore['attach']\n readonly store: OverlayStore\n}) {\n const entries = useSyncExternalStore(store.subscribe, store.entries)\n\n return (\n <View ref={attach} style={styles.fill}>\n {entries.map(([key, content]) => (\n <View key={key} style={styles.fill}>\n {content}\n </View>\n ))}\n </View>\n )\n}\n\nfunction storeFor(): OverlayStore {\n const content = new Map<string, ReactNode>()\n const listeners = new Set<() => void>()\n let entries: readonly Entry[] = []\n let layer: null | View = null\n\n const changed = () => {\n entries = [...content]\n for (const listener of listeners) {\n listener()\n }\n }\n\n return {\n attach: (view) => {\n layer = view\n },\n entries: () => entries,\n layer: () => layer,\n remove: (key) => {\n if (content.delete(key)) {\n changed()\n }\n },\n set: (key, node) => {\n content.set(key, node)\n changed()\n },\n subscribe: (listener) => {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n }\n}\n\nexport type { OverlayStore }\n\nexport { Overlay, OverlayHost, OverlayHostContext }\n"],"mappings":";;;;;AA4BA,MAAMsB,qBAAqBrB,cAAmC,IAAI;AAElE,MAAMsB,SAAShB,WAAWiB,OAAO,EAI/BC,MAAM;CACJC,QAAQ;CACRC,MAAM;CACNC,eAAe;CACfC,UAAU;CACVC,OAAO;CACPC,KAAK;AACP,EACF,CAAC;;;;;;;;AA+CD,SAAAa,YAAAX,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAqB,MAAA,EAAAC,aAAAH;CACnB,MAAA,CAAAI,SAAgBhC,SAASwC,QAAQ;CAAC,IAAAL;CAAA,IAAAN,EAAA,OAAAG,OAAA;EAK9BG,KAAA,oBAAC,cAAD;GAAsB,QAAAH,MAAKtB;GAAgBsB;EAAK,CAAA;EAAIH,EAAA,KAAAG;EAAAH,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAAA,IAAAO;CAAA,IAAAP,EAAA,OAAAE,YAAAF,EAAA,OAAAG,SAAAH,EAAA,OAAAM,IAAA;EAFtDC,KAAA,qBAAC,oBAAD;GAA2BJ,OAAAA;GAA3B,UAAA,CACGD,UACDI,EAFiB;;EAGEN,EAAA,KAAAE;EAAAF,EAAA,KAAAG;EAAAH,EAAA,KAAAM;EAAAN,EAAA,KAAAO;CAAA,OAAAA,KAAAP,EAAA;CAAA,OAHrBO;AAGqB;AAQzB,SAAAK,aAAAb,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAsB,MAAA,EAAApB,QAAAsB,UAAAJ;CAOpB,MAAAhB,UAAgBX,qBAAqB+B,MAAKjB,WAAYiB,MAAKpB,OAAQ;CAAC,IAAAuB;CAAA,IAAAN,EAAA,OAAAjB,SAAA;EAI/DuB,KAAAvB,QAAO8B,IAAKC,KAIZ;EAACd,EAAA,KAAAjB;EAAAiB,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAAA,IAAAO;CAAA,IAAAP,EAAA,OAAAnB,UAAAmB,EAAA,OAAAM,IAAA;EALJC,KAAA,oBAAC,MAAD;GAAW1B,KAAAA;GAAe,OAAAQ,OAAME;GAC7Be,UAAAA;EADE,CAAA;EAMEN,EAAA,KAAAnB;EAAAmB,EAAA,KAAAM;EAAAN,EAAA,KAAAO;CAAA,OAAAA,KAAAP,EAAA;CAAA,OANPO;AAMO;AAhBX,SAAAO,MAAAf,IAAA;CAWoB,MAAA,CAAArB,KAAAC,WAAAoB;CAAc,OAC1B,oBAAC,MAAD;EAAuB,OAAAV,OAAME;EAC1BZ,UAAAA;CADE,GAAMD,GAAN;AAEE;AAMf,SAASiC,WAAyB;CAChC,MAAMhC,0BAAU,IAAIoC,IAAuB;CAC3C,MAAMC,4BAAY,IAAIC,IAAgB;CACtC,IAAIlC,UAA4B,CAAA;CAChC,IAAID,QAAqB;CAEzB,MAAMoC,gBAAgB;EACpBnC,UAAU,CAAC,GAAGJ,OAAO;EACrB,KAAK,MAAMQ,YAAY6B,WACrB7B,SAAS;CAEb;CAEA,OAAO;EACLN,SAASsC,SAAS;GAChBrC,QAAQqC;EACV;EACApC,eAAeA;EACfD,aAAaA;EACbE,SAASN,QAAQ;GACf,IAAIC,QAAQyC,OAAO1C,GAAG,GACpBwC,QAAQ;EAEZ;EACAjC,MAAMP,KAAK2C,SAAS;GAClB1C,QAAQM,IAAIP,KAAK2C,IAAI;GACrBH,QAAQ;EACV;EACAhC,YAAYC,aAAa;GACvB6B,UAAUM,IAAInC,QAAQ;GACtB,aAAa;IACX6B,UAAUI,OAAOjC,QAAQ;GAC3B;EACF;CACF;AACF"}
|