@djangocfg/ui-core 2.1.482 → 2.1.483

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-core",
3
- "version": "2.1.482",
3
+ "version": "2.1.483",
4
4
  "description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
5
5
  "keywords": [
6
6
  "ui-components",
@@ -128,7 +128,7 @@
128
128
  "check:contrast": "node scripts/check-preset-contrast.mjs"
129
129
  },
130
130
  "peerDependencies": {
131
- "@djangocfg/i18n": "^2.1.482",
131
+ "@djangocfg/i18n": "^2.1.483",
132
132
  "consola": "^3.4.2",
133
133
  "lucide-react": "^0.545.0",
134
134
  "moment": "^2.30.1",
@@ -206,8 +206,8 @@
206
206
  "@chenglou/pretext": "^0.0.8"
207
207
  },
208
208
  "devDependencies": {
209
- "@djangocfg/i18n": "^2.1.482",
210
- "@djangocfg/typescript-config": "^2.1.482",
209
+ "@djangocfg/i18n": "^2.1.483",
210
+ "@djangocfg/typescript-config": "^2.1.483",
211
211
  "@types/node": "^24.13.3",
212
212
  "@types/react": "19.2.15",
213
213
  "@types/react-dom": "19.2.3",
@@ -144,7 +144,7 @@ const defaultLogger: BoundaryLogger = (message, error, info) => {
144
144
  };
145
145
 
146
146
  export class Boundary extends Component<BoundaryProps, BoundaryState> {
147
- state: BoundaryState = { error: null, errorInfo: null };
147
+ override state: BoundaryState = { error: null, errorInfo: null };
148
148
 
149
149
  /** Stable context value identity — recreated only when error/reset functions change (i.e. on mount). */
150
150
  private contextValue: BoundaryContextValue = {
@@ -159,7 +159,7 @@ export class Boundary extends Component<BoundaryProps, BoundaryState> {
159
159
  return { error: toError(error), errorInfo: null };
160
160
  }
161
161
 
162
- componentDidCatch(error: Error, info: ErrorInfo) {
162
+ override componentDidCatch(error: Error, info: ErrorInfo) {
163
163
  const normalized = toError(error);
164
164
  this.setState({ errorInfo: info });
165
165
 
@@ -181,7 +181,7 @@ export class Boundary extends Component<BoundaryProps, BoundaryState> {
181
181
  (this.props.logger ?? defaultLogger)(`${tag} caught error`, normalized, info);
182
182
  }
183
183
 
184
- componentDidUpdate(prevProps: BoundaryProps) {
184
+ override componentDidUpdate(prevProps: BoundaryProps) {
185
185
  if (!this.state.error) return;
186
186
  const prevKeys = prevProps.resetKeys;
187
187
  const nextKeys = this.props.resetKeys;
@@ -263,7 +263,7 @@ export class Boundary extends Component<BoundaryProps, BoundaryState> {
263
263
  }
264
264
  }
265
265
 
266
- render() {
266
+ override render() {
267
267
  if (this.state.error) {
268
268
  return this.safeRenderFallback();
269
269
  }
@@ -94,6 +94,11 @@ function applyMask(
94
94
 
95
95
  if (rawIndex < rawValue.length) {
96
96
  const char = rawValue[rawIndex];
97
+ if (char === undefined) {
98
+ masked += maskChar;
99
+ complete = false;
100
+ continue;
101
+ }
97
102
  if (part.def.pattern.test(char)) {
98
103
  const transformed = part.def.transform ? part.def.transform(char) : char;
99
104
  masked += transformed;
@@ -128,13 +133,14 @@ function extractRaw(value: string, maskParts: ReturnType<typeof parseMask>): str
128
133
  let valueIndex = 0;
129
134
  for (const part of maskParts) {
130
135
  if (valueIndex >= value.length) break;
136
+ const char = value[valueIndex];
137
+ if (char === undefined) break;
131
138
  if (part.type === "literal") {
132
- if (value[valueIndex] === part.char) {
139
+ if (char === part.char) {
133
140
  valueIndex++;
134
141
  }
135
142
  continue;
136
143
  }
137
- const char = value[valueIndex];
138
144
  if (part.def.pattern.test(char)) {
139
145
  raw += part.def.transform ? part.def.transform(char) : char;
140
146
  }
@@ -150,7 +156,7 @@ function getNextTokenIndex(
150
156
  ): number {
151
157
  let index = currentIndex + direction;
152
158
  while (index >= 0 && index < maskParts.length) {
153
- if (maskParts[index].type === "token") return index;
159
+ if (maskParts[index]?.type === "token") return index;
154
160
  index += direction;
155
161
  }
156
162
  return direction === 1 ? maskParts.length : -1;
@@ -237,7 +243,7 @@ const MaskInput = React.forwardRef<HTMLInputElement, MaskInputProps>(
237
243
  let maskPos = 0;
238
244
  let charCount = 0;
239
245
  for (let i = 0; i < maskParts.length && charCount < start; i++) {
240
- if (maskParts[i].type === "token") {
246
+ if (maskParts[i]?.type === "token") {
241
247
  charCount++;
242
248
  }
243
249
  maskPos = i + 1;
@@ -251,7 +257,7 @@ const MaskInput = React.forwardRef<HTMLInputElement, MaskInputProps>(
251
257
  }
252
258
 
253
259
  const part = maskParts[nextToken];
254
- if (part.type !== "token") {
260
+ if (!part || part.type !== "token") {
255
261
  event.preventDefault();
256
262
  return;
257
263
  }
@@ -295,7 +301,7 @@ const MaskInput = React.forwardRef<HTMLInputElement, MaskInputProps>(
295
301
  const currentRaw = extractRaw(input.value, maskParts);
296
302
  let rawIndex = 0;
297
303
  for (let i = 0; i < pos; i++) {
298
- if (maskParts[i].type === "token") rawIndex++;
304
+ if (maskParts[i]?.type === "token") rawIndex++;
299
305
  }
300
306
 
301
307
  const newRaw = currentRaw.slice(0, rawIndex) + currentRaw.slice(rawIndex + 1);
@@ -318,7 +324,7 @@ const MaskInput = React.forwardRef<HTMLInputElement, MaskInputProps>(
318
324
  const currentRaw = extractRaw(input.value, maskParts);
319
325
  let rawIndex = 0;
320
326
  for (let i = 0; i < start; i++) {
321
- if (maskParts[i].type === "token") rawIndex++;
327
+ if (maskParts[i]?.type === "token") rawIndex++;
322
328
  }
323
329
 
324
330
  if (rawIndex >= currentRaw.length) return;
@@ -357,13 +363,13 @@ const MaskInput = React.forwardRef<HTMLInputElement, MaskInputProps>(
357
363
  if (nextToken === -1 || nextToken >= maskParts.length) return;
358
364
 
359
365
  const part = maskParts[nextToken];
360
- if (part.type !== "token") return;
366
+ if (!part || part.type !== "token") return;
361
367
  if (!part.def.pattern.test(char)) return;
362
368
 
363
369
  const currentRaw = extractRaw(input.value, maskParts);
364
370
  let rawIndex = 0;
365
371
  for (let i = 0; i < nextToken; i++) {
366
- if (maskParts[i].type === "token") rawIndex++;
372
+ if (maskParts[i]?.type === "token") rawIndex++;
367
373
  }
368
374
 
369
375
  const transformed = part.def.transform ? part.def.transform(char) : char;
@@ -383,7 +389,7 @@ const MaskInput = React.forwardRef<HTMLInputElement, MaskInputProps>(
383
389
  const filledCount = rawValue.length;
384
390
  let tokenSeen = 0;
385
391
  for (let i = 0; i < maskParts.length; i++) {
386
- if (maskParts[i].type === "token") {
392
+ if (maskParts[i]?.type === "token") {
387
393
  if (tokenSeen === filledCount) return i;
388
394
  tokenSeen++;
389
395
  }
@@ -47,8 +47,11 @@ export interface TimePickerProps {
47
47
  function parseTime(timeStr: string): { hours: number; minutes: number } | null {
48
48
  const match = timeStr.match(/^(\d{1,2}):(\d{2})$/);
49
49
  if (!match) return null;
50
- const hours = parseInt(match[1], 10);
51
- const minutes = parseInt(match[2], 10);
50
+ const hoursPart = match[1];
51
+ const minutesPart = match[2];
52
+ if (hoursPart === undefined || minutesPart === undefined) return null;
53
+ const hours = parseInt(hoursPart, 10);
54
+ const minutes = parseInt(minutesPart, 10);
52
55
  if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;
53
56
  return { hours, minutes };
54
57
  }
@@ -34,7 +34,8 @@
34
34
  export function getIntensity(value: number, thresholds: number[]): number {
35
35
  if (!(value > 0)) return 0;
36
36
  for (let i = 0; i < thresholds.length; i++) {
37
- if (value <= thresholds[i]) return i + 1;
37
+ const threshold = thresholds[i];
38
+ if (threshold !== undefined && value <= threshold) return i + 1;
38
39
  }
39
40
  return thresholds.length;
40
41
  }
@@ -19,10 +19,14 @@ function parseHslString(hsl: string): { h: number; s: number; l: number } | null
19
19
  .replace(/\s*\/\s*[\d.]+%?$/, ''); // drop optional `/ alpha`
20
20
  const match = stripped.match(/^(-?\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%$/);
21
21
  if (!match) return null;
22
+ const hue = match[1];
23
+ const saturation = match[2];
24
+ const lightness = match[3];
25
+ if (hue === undefined || saturation === undefined || lightness === undefined) return null;
22
26
  return {
23
- h: parseFloat(match[1]),
24
- s: parseFloat(match[2]),
25
- l: parseFloat(match[3]),
27
+ h: parseFloat(hue),
28
+ s: parseFloat(saturation),
29
+ l: parseFloat(lightness),
26
30
  };
27
31
  }
28
32