@djangocfg/ui-core 2.1.541 → 2.1.543

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 (48) hide show
  1. package/README.md +3 -1
  2. package/package.json +12 -9
  3. package/src/components/data/BalancedText/hooks/useMaxLinesWidth.ts +4 -25
  4. package/src/components/forms/button-download/index.tsx +1 -1
  5. package/src/components/forms/datetime-field/date-time-field.tsx +1 -1
  6. package/src/components/forms/editable/index.tsx +7 -3
  7. package/src/components/forms/input-group/index.tsx +12 -0
  8. package/src/components/forms/mask-input/index.tsx +7 -3
  9. package/src/components/forms/money-field/README.md +79 -0
  10. package/src/components/forms/money-field/index.tsx +288 -0
  11. package/src/components/forms/otp/use-otp-input.ts +1 -1
  12. package/src/components/forms/tags-input/index.tsx +55 -41
  13. package/src/components/forms/time-picker/index.tsx +7 -3
  14. package/src/components/index.ts +4 -0
  15. package/src/components/layout/key-value/index.tsx +9 -7
  16. package/src/components/layout/resizable/index.tsx +6 -1
  17. package/src/components/navigation/command/index.tsx +24 -6
  18. package/src/components/navigation/link/LinkContext.tsx +3 -1
  19. package/src/components/navigation/pagination/pagination-static.tsx +1 -1
  20. package/src/components/navigation/tabs/index.tsx +30 -9
  21. package/src/components/overlay/responsive-sheet/index.tsx +4 -4
  22. package/src/components/select/helpers.tsx +1 -1
  23. package/src/components/select/multi-select-pro-async.tsx +13 -6
  24. package/src/components/select/multi-select-pro.tsx +3 -4
  25. package/src/components/specialized/flag/Flag.tsx +11 -5
  26. package/src/components/specialized/flag/flag-map.ts +13 -7
  27. package/src/components/specialized/image-with-fallback/index.tsx +9 -4
  28. package/src/components/specialized/presence/index.tsx +2 -3
  29. package/src/components/specialized/token-icon/index.tsx +26 -13
  30. package/src/hooks/audio/useAudioPrefs.ts +8 -3
  31. package/src/hooks/device/useBrowserDetect.ts +5 -1
  32. package/src/hooks/dom/useImageLoader.ts +24 -20
  33. package/src/hooks/dom/useScroll.ts +7 -6
  34. package/src/hooks/events/useEventsBus.ts +19 -5
  35. package/src/hooks/hotkey/useHotkeyChord.ts +11 -4
  36. package/src/hooks/hotkey/useHotkeyHelp.ts +8 -3
  37. package/src/hooks/router/adapter.tsx +3 -1
  38. package/src/hooks/state/storage-quota.ts +27 -0
  39. package/src/hooks/state/useDebouncedCallback.ts +26 -20
  40. package/src/hooks/state/useLocalStorage.ts +7 -13
  41. package/src/hooks/state/useSessionStorage.ts +7 -9
  42. package/src/lib/compose-event-handlers.ts +5 -5
  43. package/src/lib/dialog-service/getDialog.ts +1 -1
  44. package/src/lib/get-element-ref.ts +9 -6
  45. package/src/lib/pretext/pretext.types.ts +25 -70
  46. package/src/lib/pretext/use-pretext.ts +8 -12
  47. package/src/snippets/LazyComponent.tsx +9 -9
  48. package/src/styles/palette/useThemePalette.ts +7 -0
@@ -30,7 +30,7 @@ export function getDialog(): DialogAPI | null {
30
30
  if (!api) {
31
31
  if (process.env.NODE_ENV !== 'production' && !warnedMissing) {
32
32
  warnedMissing = true;
33
- // eslint-disable-next-line no-console
33
+
34
34
  console.warn(
35
35
  '[getDialog] window.dialog is not available — mount <DialogProvider /> at the app root.',
36
36
  );
@@ -3,17 +3,21 @@
3
3
  import * as React from "react";
4
4
 
5
5
  /**
6
- * Get the ref from a React element without throwing warnings.
6
+ * React 18 exposed `ref` on the element itself; React 19 moved it into `props`.
7
+ * Neither placement is in `ReactElement`'s public type, so the legacy one is
8
+ * declared here rather than asserted away.
7
9
  */
8
- function getElementRef(element: React.ReactElement) {
10
+ type ElementWithLegacyRef = React.ReactElement & { ref?: React.Ref<unknown> };
11
+
12
+ /** Get the ref from a React element without throwing warnings. */
13
+ function getElementRef(element: ElementWithLegacyRef) {
9
14
  if (!React.isValidElement(element)) return undefined;
10
15
 
11
16
  // React <=18 in DEV
12
17
  let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
13
18
  let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
14
19
  if (mayWarn) {
15
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
- return (element as any).ref;
20
+ return element.ref;
17
21
  }
18
22
 
19
23
  // React 19 in DEV
@@ -25,8 +29,7 @@ function getElementRef(element: React.ReactElement) {
25
29
 
26
30
  // Not DEV
27
31
  return (
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- (element.props as { ref?: React.Ref<unknown> }).ref || (element as any).ref
32
+ (element.props as { ref?: React.Ref<unknown> }).ref || element.ref
30
33
  );
31
34
  }
32
35
 
@@ -1,72 +1,27 @@
1
1
  // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
2
  //
3
- // Local mirror of the @chenglou/pretext public API. The runtime dependency
4
- // is declared `optional` (see ui-tools/package.json), so consumers that
5
- // never use BalancedText / pretext-powered tools don't pay for it. To keep
6
- // `pnpm check` green without the dependency installed, we redeclare just
7
- // the types we touch — no `import type from '@chenglou/pretext'`.
8
- //
9
- // Mirrors the public surface as of @chenglou/pretext 0.0.7. If the upstream
10
- // types drift, update here.
11
-
12
- export interface PrepareOptions {
13
- whiteSpace?: 'normal' | 'pre' | 'pre-wrap' | 'pre-line';
14
- }
15
-
16
- // Opaque handles — internal shape doesn't matter to consumers of the hooks.
17
- // We brand them so the two flavours don't get accidentally swapped.
18
- export interface PreparedText {
19
- readonly __brand: 'PreparedText';
20
- }
21
-
22
- export interface PreparedTextWithSegments {
23
- readonly __brand: 'PreparedTextWithSegments';
24
- }
25
-
26
- export interface LayoutResult {
27
- lineCount: number;
28
- height: number;
29
- }
30
-
31
- export interface LayoutLine {
32
- text: string;
33
- width: number;
34
- start: number;
35
- end: number;
36
- }
37
-
38
- export interface LayoutLinesResult {
39
- lineCount: number;
40
- height: number;
41
- lines: LayoutLine[];
42
- }
43
-
44
- export interface WalkLineRange {
45
- width: number;
46
- start: number;
47
- end: number;
48
- }
49
-
50
- export interface PretextModule {
51
- prepare(text: string, font: string, options?: PrepareOptions): PreparedText;
52
- prepareWithSegments(
53
- text: string,
54
- font: string,
55
- options?: PrepareOptions,
56
- ): PreparedTextWithSegments;
57
- layout(
58
- prepared: PreparedText,
59
- maxWidth: number,
60
- lineHeight: number,
61
- ): LayoutResult;
62
- layoutWithLines(
63
- prepared: PreparedTextWithSegments,
64
- maxWidth: number,
65
- lineHeight: number,
66
- ): LayoutLinesResult;
67
- walkLineRanges(
68
- prepared: PreparedTextWithSegments,
69
- maxWidth: number,
70
- visit: (line: WalkLineRange) => void,
71
- ): void;
72
- }
3
+ // Re-export of the @chenglou/pretext public types. A hand-written mirror used
4
+ // to live here to keep `pnpm check` green while the runtime was an optional
5
+ // dependency; it is a hard `dependencies` entry now, and the mirror had already
6
+ // drifted — it declared `LayoutLine.start/end` as `number` where upstream
7
+ // returns a `{ segmentIndex, graphemeIndex }` cursor, so every consumer of
8
+ // `usePretextLines` was typed against a shape the runtime never produces.
9
+
10
+ export type {
11
+ PrepareOptions,
12
+ PreparedText,
13
+ PreparedTextWithSegments,
14
+ LayoutResult,
15
+ LayoutLine,
16
+ LayoutLineRange,
17
+ LayoutLinesResult,
18
+ LayoutCursor,
19
+ } from '@chenglou/pretext';
20
+
21
+ import type * as pretext from '@chenglou/pretext';
22
+
23
+ /** The subset of the module surface the hooks in this folder call. */
24
+ export type PretextModule = Pick<
25
+ typeof pretext,
26
+ 'prepare' | 'prepareWithSegments' | 'layout' | 'layoutWithLines' | 'walkLineRanges'
27
+ >;
@@ -6,15 +6,16 @@
6
6
  //
7
7
  // Powered by Pretext by Cheng Lou — github.com/chenglou/pretext
8
8
  //
9
- // `@chenglou/pretext` is declared as an optionalDependency in
10
- // `packages/ui-tools/package.json` — consumers that never use BalancedText
11
- // (or other pretext-based tools) can install ui-tools without it. The
12
- // `getPretext()` helper uses a CommonJS `require()` so the optional
13
- // dependency is resolved lazily at first use; if it is missing, the
14
- // `require` throws at call site, never at module-load.
9
+ // `@chenglou/pretext` is imported statically because it is ESM-only
10
+ // (`"type": "module"`, and its `exports` map offers only an `import`
11
+ // condition). The previous lazy `require('@chenglou/pretext')` could not
12
+ // resolve it in any runtime: under Vite/ESM `require` is not defined at all,
13
+ // so the first render of `BalancedText` threw `require is not defined`
14
+ // rather than degrading gracefully.
15
15
 
16
16
  'use client';
17
17
 
18
+ import * as pretext from '@chenglou/pretext';
18
19
  import * as React from 'react';
19
20
  import type {
20
21
  PreparedText,
@@ -35,13 +36,8 @@ export type {
35
36
 
36
37
  const isBrowser = typeof window !== 'undefined';
37
38
 
38
- let cachedPretext: PretextModule | null = null;
39
-
40
39
  function getPretext(): PretextModule {
41
- if (cachedPretext) return cachedPretext;
42
- // eslint-disable-next-line @typescript-eslint/no-require-imports
43
- cachedPretext = require('@chenglou/pretext') as PretextModule;
44
- return cachedPretext;
40
+ return pretext;
45
41
  }
46
42
 
47
43
  const EMPTY_LAYOUT: LayoutResult = { lineCount: 0, height: 0 };
@@ -7,7 +7,7 @@
7
7
 
8
8
  'use client';
9
9
 
10
- import React, { Suspense, ReactNode, ComponentType, lazy } from 'react';
10
+ import React, { Suspense, ReactNode, ComponentType, LazyExoticComponent, lazy } from 'react';
11
11
 
12
12
  // Default loading spinner
13
13
  export const DefaultLoader = () => (
@@ -67,13 +67,13 @@ export function LazyWrapper({ children, fallback }: LazyWrapperProps) {
67
67
  * <HeavyComponent someProps={value} />
68
68
  * ```
69
69
  */
70
- export function createLazyComponent<T extends ComponentType<any>>(
71
- importFn: () => Promise<{ default: T }>,
70
+ export function createLazyComponent<P extends object>(
71
+ importFn: () => Promise<{ default: ComponentType<P> }>,
72
72
  fallback?: ReactNode
73
73
  ) {
74
74
  const LazyComponent = lazy(importFn);
75
75
 
76
- return function WrappedLazyComponent(props: React.ComponentProps<T>) {
76
+ return function WrappedLazyComponent(props: P) {
77
77
  return (
78
78
  <Suspense fallback={fallback ?? <DefaultLoader />}>
79
79
  <LazyComponent {...props} />
@@ -95,18 +95,18 @@ export function createLazyComponent<T extends ComponentType<any>>(
95
95
  * ```
96
96
  */
97
97
  export function createLazyNamedComponent<
98
- T extends Record<string, ComponentType<any>>,
99
- K extends keyof T
98
+ P extends object,
99
+ K extends string = string
100
100
  >(
101
- importFn: () => Promise<T>,
101
+ importFn: () => Promise<Record<K, ComponentType<P>>>,
102
102
  exportName: K,
103
103
  fallback?: ReactNode
104
104
  ) {
105
- const LazyComponent = lazy(() =>
105
+ const LazyComponent: LazyExoticComponent<ComponentType<P>> = lazy(() =>
106
106
  importFn().then((mod) => ({ default: mod[exportName] }))
107
107
  );
108
108
 
109
- return function WrappedLazyComponent(props: React.ComponentProps<T[K]>) {
109
+ return function WrappedLazyComponent(props: P) {
110
110
  return (
111
111
  <Suspense fallback={fallback ?? <DefaultLoader />}>
112
112
  <LazyComponent {...props} />
@@ -101,6 +101,13 @@ export function useThemePalette(): ThemePalette {
101
101
  const theme = useResolvedTheme();
102
102
 
103
103
  return useMemo(() => {
104
+ // `theme` is read here so the dependency is real to the linter as well as to
105
+ // us: every getCssColorAsHex call below resolves against the live DOM, whose
106
+ // values change when the theme flips, but nothing in that call chain
107
+ // mentions `theme`. Without this read the memo looks free of it and would be
108
+ // cached across a theme change, returning the previous theme's colors.
109
+ void theme;
110
+
104
111
  return {
105
112
  // Base colors
106
113
  background: getCssColorAsHex('background'),