@stonecrop/aform 0.21.0 → 0.23.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.
@@ -0,0 +1,94 @@
1
+ import type { BadgeDescriptor, FieldOptions } from '@stonecrop/schema'
2
+ import { isBadgeDescriptor, lookupBadge } from '@stonecrop/schema'
3
+
4
+ import { deserializeFunction } from './deserialize'
5
+
6
+ /**
7
+ * Row context passed to badge `format` functions in form fields.
8
+ * @public
9
+ */
10
+ export type BadgeFormatContext = {
11
+ record?: Record<string, unknown>
12
+ row?: Record<string, unknown>
13
+ }
14
+
15
+ /**
16
+ * Badge-aware field `format` function signature.
17
+ * @public
18
+ */
19
+ export type BadgeFormatFn = (value: unknown, context: BadgeFormatContext) => string | BadgeDescriptor
20
+
21
+ /**
22
+ * Resolve a field value to a badge descriptor using format (if present) then options map.
23
+ * @public
24
+ */
25
+ export function resolveFieldBadge(
26
+ value: unknown,
27
+ options: FieldOptions | undefined,
28
+ format: string | BadgeFormatFn | undefined,
29
+ context: BadgeFormatContext = {}
30
+ ): BadgeDescriptor | undefined {
31
+ if (format) {
32
+ let formatted: unknown
33
+ if (typeof format === 'function') {
34
+ formatted = format(value, context)
35
+ } else {
36
+ const formatFn = deserializeFunction<BadgeFormatFn>(format)
37
+ formatted = formatFn(value, context)
38
+ }
39
+ if (isBadgeDescriptor(formatted)) {
40
+ const label = formatted.label.trim()
41
+ return label ? formatted : undefined
42
+ }
43
+ if (typeof formatted === 'string' && formatted !== '') {
44
+ return lookupBadge(options, formatted) ?? { label: formatted, variant: 'neutral' }
45
+ }
46
+ }
47
+
48
+ const key = badgeLookupKey(value)
49
+ if (key === undefined) return undefined
50
+ return lookupBadge(options, key)
51
+ }
52
+
53
+ /**
54
+ * Stored choice value as an options-map key. Only primitives can match a declared choice, so
55
+ * anything else yields undefined rather than the '[object Object]' that String() would produce.
56
+ */
57
+ function badgeLookupKey(value: unknown): string | undefined {
58
+ switch (typeof value) {
59
+ case 'string':
60
+ return value === '' ? undefined : value
61
+ case 'number':
62
+ case 'boolean':
63
+ case 'bigint':
64
+ return String(value)
65
+ default:
66
+ return undefined
67
+ }
68
+ }
69
+
70
+ const BADGE_VARIANTS = new Set<string>(['neutral', 'success', 'warning', 'danger', 'brand'])
71
+
72
+ /**
73
+ * CSS custom properties for input-accent styling on a native input.
74
+ * @public
75
+ */
76
+ export function badgeInputAccentStyle(descriptor: BadgeDescriptor | undefined): Record<string, string> | undefined {
77
+ if (!descriptor?.label?.trim()) return undefined
78
+ const variant = descriptor.variant ?? 'neutral'
79
+ if (descriptor.color) {
80
+ return {
81
+ borderLeftWidth: '4px',
82
+ borderLeftStyle: 'solid',
83
+ borderLeftColor: descriptor.color,
84
+ paddingLeft: 'calc(1ch - 4px)',
85
+ }
86
+ }
87
+ if (!BADGE_VARIANTS.has(variant)) return undefined
88
+ return {
89
+ borderLeftWidth: '4px',
90
+ borderLeftStyle: 'solid',
91
+ borderLeftColor: `var(--sc-badge-${variant}-accent)`,
92
+ paddingLeft: 'calc(1ch - 4px)',
93
+ }
94
+ }