@asteby/metacore-runtime-react 49.5.0 → 49.7.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.
- package/CHANGELOG.md +12 -0
- package/dist/business/customer-picker.d.ts +8 -2
- package/dist/business/customer-picker.d.ts.map +1 -1
- package/dist/business/customer-picker.js +30 -27
- package/dist/business/index.d.ts +1 -0
- package/dist/business/index.d.ts.map +1 -1
- package/dist/business/index.js +1 -0
- package/dist/business/line-product-cell.d.ts +8 -10
- package/dist/business/line-product-cell.d.ts.map +1 -1
- package/dist/business/line-product-cell.js +13 -90
- package/dist/business/product-options.d.ts +41 -0
- package/dist/business/product-options.d.ts.map +1 -0
- package/dist/business/product-options.js +58 -0
- package/dist/business/product-picker.d.ts +5 -1
- package/dist/business/product-picker.d.ts.map +1 -1
- package/dist/business/product-picker.js +26 -35
- package/dist/business/relate-documents.d.ts +1 -1
- package/dist/business/relate-documents.d.ts.map +1 -1
- package/dist/business/relate-documents.js +6 -8
- package/dist/business/vehicle-picker.d.ts +8 -2
- package/dist/business/vehicle-picker.d.ts.map +1 -1
- package/dist/business/vehicle-picker.js +28 -28
- package/dist/dialogs/dynamic-record.d.ts.map +1 -1
- package/dist/dialogs/dynamic-record.js +28 -43
- package/dist/dynamic-multi-select-field.d.ts.map +1 -1
- package/dist/dynamic-multi-select-field.js +36 -6
- package/dist/dynamic-select-field.d.ts +9 -23
- package/dist/dynamic-select-field.d.ts.map +1 -1
- package/dist/dynamic-select-field.js +105 -172
- package/dist/entity-select.d.ts +5 -2
- package/dist/entity-select.d.ts.map +1 -1
- package/dist/entity-select.js +23 -116
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/query-batch.d.ts.map +1 -1
- package/dist/query-batch.js +4 -0
- package/dist/record-picker-actions.d.ts +40 -2
- package/dist/record-picker-actions.d.ts.map +1 -1
- package/dist/record-picker-actions.js +44 -4
- package/dist/record-picker-dialog.d.ts +23 -0
- package/dist/record-picker-dialog.d.ts.map +1 -0
- package/dist/record-picker-dialog.js +37 -0
- package/dist/record-picker-option.d.ts +25 -0
- package/dist/record-picker-option.d.ts.map +1 -0
- package/dist/record-picker-option.js +55 -0
- package/dist/record-picker.d.ts +149 -0
- package/dist/record-picker.d.ts.map +1 -0
- package/dist/record-picker.js +372 -0
- package/dist/use-option-ids.d.ts +34 -0
- package/dist/use-option-ids.d.ts.map +1 -0
- package/dist/use-option-ids.js +138 -0
- package/dist/use-options-resolver.d.ts +4 -0
- package/dist/use-options-resolver.d.ts.map +1 -1
- package/dist/use-options-resolver.js +10 -1
- package/package.json +1 -1
- package/src/__tests__/business-pickers.test.tsx +6 -3
- package/src/__tests__/document-editor-inline-selects.test.tsx +2 -1
- package/src/__tests__/document-form-dialog.test.tsx +4 -3
- package/src/__tests__/document-lines-grid.test.tsx +2 -1
- package/src/__tests__/edit-field-polish.test.tsx +6 -3
- package/src/__tests__/option-ids.test.tsx +181 -0
- package/src/__tests__/record-picker.test.tsx +469 -0
- package/src/business/customer-picker.tsx +87 -98
- package/src/business/index.ts +1 -0
- package/src/business/line-product-cell.tsx +55 -180
- package/src/business/product-options.tsx +119 -0
- package/src/business/product-picker.tsx +63 -126
- package/src/business/relate-documents.tsx +36 -45
- package/src/business/vehicle-picker.tsx +76 -99
- package/src/dialogs/dynamic-record.tsx +44 -97
- package/src/dynamic-multi-select-field.tsx +53 -15
- package/src/dynamic-select-field.tsx +188 -379
- package/src/entity-select.tsx +53 -202
- package/src/index.ts +35 -2
- package/src/query-batch.ts +3 -0
- package/src/record-picker-actions.tsx +101 -8
- package/src/record-picker-dialog.tsx +80 -0
- package/src/record-picker-option.tsx +96 -0
- package/src/record-picker.tsx +971 -0
- package/src/use-option-ids.ts +168 -0
- package/src/use-options-resolver.ts +11 -1
- package/dist/business/use-async-search.d.ts +0 -10
- package/dist/business/use-async-search.d.ts.map +0 -1
- package/dist/business/use-async-search.js +0 -38
- package/src/business/use-async-search.ts +0 -43
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Option visuals shared by every RecordPicker configuration: a thumbnail
|
|
2
|
+
// (image / lucide icon name / initials fallback) and the leading visual of an
|
|
3
|
+
// option (image, else icon, else color dot, else initials).
|
|
4
|
+
import { useState } from 'react'
|
|
5
|
+
import { InitialsAvatar } from '@asteby/metacore-ui/primitives'
|
|
6
|
+
import { resolveColorCss } from '@asteby/metacore-ui/lib'
|
|
7
|
+
import { DynamicIcon, isLucideIconName } from './dynamic-icon'
|
|
8
|
+
import type { ResolvedOption } from './use-options-resolver'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Small square thumbnail for an option's `image`. When the option has no image
|
|
12
|
+
* it falls back to a deterministic initials avatar (shared `InitialsAvatar`)
|
|
13
|
+
* derived from `name`, so an imageless reference reads as a colored badge rather
|
|
14
|
+
* than an empty placeholder — and rows/triggers stay aligned. `size` is in
|
|
15
|
+
* pixels (kept small — 20–24px — so the picker reads as a list, not a gallery).
|
|
16
|
+
* Inline style for the box dimensions: arbitrary Tailwind classes from a
|
|
17
|
+
* federated addon don't always survive the host's class scan.
|
|
18
|
+
*/
|
|
19
|
+
export function OptionThumb({
|
|
20
|
+
image,
|
|
21
|
+
name,
|
|
22
|
+
size = 20,
|
|
23
|
+
}: {
|
|
24
|
+
image?: string | null
|
|
25
|
+
name?: string | null
|
|
26
|
+
size?: number
|
|
27
|
+
}) {
|
|
28
|
+
const [broken, setBroken] = useState(false)
|
|
29
|
+
const box = { width: size, height: size }
|
|
30
|
+
// Missing or 404 image (bare avatar filenames often 404) → initials, never
|
|
31
|
+
// an invisible box that looks like "no avatar".
|
|
32
|
+
if (!image || broken) {
|
|
33
|
+
return <InitialsAvatar name={name} size={size} rounded="sm" tone="neutral" />
|
|
34
|
+
}
|
|
35
|
+
// A lucide icon name stored where an image url/path is expected (the `icon`
|
|
36
|
+
// form widget's icon mode) → render the glyph instead of a broken <img>.
|
|
37
|
+
if (isLucideIconName(image)) {
|
|
38
|
+
return (
|
|
39
|
+
<span className="flex shrink-0 items-center justify-center rounded-sm bg-muted" style={box} aria-hidden>
|
|
40
|
+
<DynamicIcon name={image} className="size-4" />
|
|
41
|
+
</span>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
return (
|
|
45
|
+
<img
|
|
46
|
+
src={image}
|
|
47
|
+
alt=""
|
|
48
|
+
aria-hidden
|
|
49
|
+
loading="lazy"
|
|
50
|
+
className="shrink-0 rounded-sm object-cover"
|
|
51
|
+
style={box}
|
|
52
|
+
onError={() => setBroken(true)}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Leading visual for an option: a photo thumbnail (FK relations with an image),
|
|
59
|
+
* else a declared icon, else a color dot (enum/status options with a color).
|
|
60
|
+
* Returns null when the option carries none, so plain text options stay plain.
|
|
61
|
+
*/
|
|
62
|
+
export function OptionLead({
|
|
63
|
+
option,
|
|
64
|
+
size = 20,
|
|
65
|
+
}: {
|
|
66
|
+
option?: Pick<ResolvedOption, 'image' | 'color' | 'icon' | 'label'> | null
|
|
67
|
+
size?: number
|
|
68
|
+
}) {
|
|
69
|
+
if (!option) return null
|
|
70
|
+
if (option.image) return <OptionThumb image={option.image} name={option.label} size={size} />
|
|
71
|
+
if (option.icon) {
|
|
72
|
+
return (
|
|
73
|
+
<span
|
|
74
|
+
className="flex shrink-0 items-center justify-center"
|
|
75
|
+
style={{ width: size, height: size, color: option.color ? resolveColorCss(option.color) : undefined }}
|
|
76
|
+
aria-hidden
|
|
77
|
+
>
|
|
78
|
+
<DynamicIcon name={option.icon} className="size-4" />
|
|
79
|
+
</span>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
if (option.color) {
|
|
83
|
+
return (
|
|
84
|
+
<span
|
|
85
|
+
className="shrink-0 rounded-full"
|
|
86
|
+
style={{ width: Math.round(size * 0.5), height: Math.round(size * 0.5), background: resolveColorCss(option.color) }}
|
|
87
|
+
aria-hidden
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
// No image/icon/color: an imageless reference option. Show its initials
|
|
92
|
+
// (shared InitialsAvatar) so it stays visually aligned with the sibling
|
|
93
|
+
// options that DO carry a thumbnail, rather than a blank gap.
|
|
94
|
+
if (option.label) return <InitialsAvatar name={option.label} size={size} rounded="sm" tone="neutral" />
|
|
95
|
+
return null
|
|
96
|
+
}
|