@santi020k/lumen-core 3.0.1 → 4.1.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.
Files changed (153) hide show
  1. package/PHONE_FLAG_LICENSE.txt +21 -0
  2. package/README.md +384 -3
  3. package/THIRD_PARTY_NOTICES.md +16 -2
  4. package/dist/ai-surfaces.d.ts +25 -0
  5. package/dist/ai-surfaces.d.ts.map +1 -0
  6. package/dist/ai-surfaces.js +162 -0
  7. package/dist/amount-field.d.ts +22 -0
  8. package/dist/amount-field.d.ts.map +1 -0
  9. package/dist/amount-field.js +207 -0
  10. package/dist/attachments.d.ts +15 -0
  11. package/dist/attachments.d.ts.map +1 -0
  12. package/dist/attachments.js +123 -0
  13. package/dist/bullet-chart.d.ts +33 -0
  14. package/dist/bullet-chart.d.ts.map +1 -0
  15. package/dist/bullet-chart.js +80 -0
  16. package/dist/chart-activation.d.ts +32 -0
  17. package/dist/chart-activation.d.ts.map +1 -0
  18. package/dist/chart-activation.js +97 -0
  19. package/dist/chart-interaction.d.ts +12 -0
  20. package/dist/chart-interaction.d.ts.map +1 -0
  21. package/dist/chart-interaction.js +274 -0
  22. package/dist/chart-models.d.ts +156 -0
  23. package/dist/chart-models.d.ts.map +1 -0
  24. package/dist/chart-models.js +348 -0
  25. package/dist/chart-motion.d.ts +6 -0
  26. package/dist/chart-motion.d.ts.map +1 -0
  27. package/dist/chart-motion.js +107 -0
  28. package/dist/charts.d.ts +58 -3
  29. package/dist/charts.d.ts.map +1 -1
  30. package/dist/charts.js +247 -18
  31. package/dist/code.js +1 -1
  32. package/dist/combobox.d.ts +7 -0
  33. package/dist/combobox.d.ts.map +1 -0
  34. package/dist/combobox.js +253 -0
  35. package/dist/comparison-chart.d.ts +32 -0
  36. package/dist/comparison-chart.d.ts.map +1 -0
  37. package/dist/comparison-chart.js +64 -0
  38. package/dist/components.d.ts +210 -25
  39. package/dist/components.d.ts.map +1 -1
  40. package/dist/components.js +102 -26
  41. package/dist/dashboard.d.ts +16 -0
  42. package/dist/dashboard.d.ts.map +1 -0
  43. package/dist/dashboard.js +21 -0
  44. package/dist/data.d.ts.map +1 -1
  45. package/dist/data.js +21 -5
  46. package/dist/dates.d.ts +13 -0
  47. package/dist/dates.d.ts.map +1 -0
  48. package/dist/dates.js +37 -0
  49. package/dist/device-frame.d.ts +25 -0
  50. package/dist/device-frame.d.ts.map +1 -0
  51. package/dist/device-frame.js +50 -0
  52. package/dist/direction.d.ts +3 -0
  53. package/dist/direction.d.ts.map +1 -0
  54. package/dist/direction.js +10 -0
  55. package/dist/extended-charts.d.ts +95 -0
  56. package/dist/extended-charts.d.ts.map +1 -0
  57. package/dist/extended-charts.js +175 -0
  58. package/dist/figma.d.ts.map +1 -1
  59. package/dist/figma.js +10 -1
  60. package/dist/floating-panel.d.ts +24 -0
  61. package/dist/floating-panel.d.ts.map +1 -0
  62. package/dist/floating-panel.js +203 -0
  63. package/dist/forms.d.ts.map +1 -1
  64. package/dist/forms.js +18 -4
  65. package/dist/icon-data.generated.d.ts +1 -1
  66. package/dist/icon-data.generated.d.ts.map +1 -1
  67. package/dist/icon-data.generated.js +1 -1
  68. package/dist/icons.js +3 -4
  69. package/dist/illustrations.generated.d.ts +1 -1
  70. package/dist/image-comparison.d.ts +14 -0
  71. package/dist/image-comparison.d.ts.map +1 -0
  72. package/dist/image-comparison.js +48 -0
  73. package/dist/index.d.ts +37 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +36 -3
  76. package/dist/loading.d.ts +34 -0
  77. package/dist/loading.d.ts.map +1 -0
  78. package/dist/loading.js +70 -0
  79. package/dist/media-viewport.d.ts +24 -0
  80. package/dist/media-viewport.d.ts.map +1 -0
  81. package/dist/media-viewport.js +119 -0
  82. package/dist/media-workspace.d.ts +27 -0
  83. package/dist/media-workspace.d.ts.map +1 -0
  84. package/dist/media-workspace.js +83 -0
  85. package/dist/message-scroller.d.ts +14 -0
  86. package/dist/message-scroller.d.ts.map +1 -0
  87. package/dist/message-scroller.js +113 -0
  88. package/dist/motion-workflows.d.ts +24 -0
  89. package/dist/motion-workflows.d.ts.map +1 -0
  90. package/dist/motion-workflows.js +220 -0
  91. package/dist/motion.d.ts +12 -0
  92. package/dist/motion.d.ts.map +1 -0
  93. package/dist/motion.js +96 -0
  94. package/dist/native-input.d.ts +25 -0
  95. package/dist/native-input.d.ts.map +1 -0
  96. package/dist/native-input.js +188 -0
  97. package/dist/phone-flags.generated.d.ts +2 -0
  98. package/dist/phone-flags.generated.d.ts.map +1 -0
  99. package/dist/phone-flags.generated.js +263 -0
  100. package/dist/phone.d.ts +4 -0
  101. package/dist/phone.d.ts.map +1 -1
  102. package/dist/phone.js +6 -1
  103. package/dist/rich-text.d.ts +7 -0
  104. package/dist/rich-text.d.ts.map +1 -1
  105. package/dist/rich-text.js +13 -0
  106. package/dist/rive.d.ts +37 -0
  107. package/dist/rive.d.ts.map +1 -0
  108. package/dist/rive.js +129 -0
  109. package/dist/schedule.d.ts.map +1 -1
  110. package/dist/schedule.js +63 -23
  111. package/dist/tab-indicator.d.ts +3 -0
  112. package/dist/tab-indicator.d.ts.map +1 -0
  113. package/dist/tab-indicator.js +57 -0
  114. package/dist/theme-audit.d.ts +16 -0
  115. package/dist/theme-audit.d.ts.map +1 -0
  116. package/dist/theme-audit.js +57 -0
  117. package/dist/theme-builder.d.ts +7 -1
  118. package/dist/theme-builder.d.ts.map +1 -1
  119. package/dist/theme-builder.js +45 -23
  120. package/dist/theme-presets.generated.d.ts +217 -0
  121. package/dist/theme-presets.generated.d.ts.map +1 -0
  122. package/dist/theme-presets.generated.js +231 -0
  123. package/dist/theme.d.ts +11 -3
  124. package/dist/theme.d.ts.map +1 -1
  125. package/dist/theme.js +56 -6
  126. package/dist/virtual-collection.d.ts +14 -0
  127. package/dist/virtual-collection.d.ts.map +1 -0
  128. package/dist/virtual-collection.js +132 -0
  129. package/dist/virtual-list.d.ts +7 -0
  130. package/dist/virtual-list.d.ts.map +1 -0
  131. package/dist/virtual-list.js +135 -0
  132. package/dist/virtual-window.d.ts +19 -0
  133. package/dist/virtual-window.d.ts.map +1 -0
  134. package/dist/virtual-window.js +84 -0
  135. package/dist/visual-effects.d.ts +6 -0
  136. package/dist/visual-effects.d.ts.map +1 -0
  137. package/dist/visual-effects.js +44 -0
  138. package/dist/world-map-data.generated.d.ts +9 -0
  139. package/dist/world-map-data.generated.d.ts.map +1 -0
  140. package/dist/world-map-data.generated.js +240 -0
  141. package/dist/world-map-navigation.d.ts +16 -0
  142. package/dist/world-map-navigation.d.ts.map +1 -0
  143. package/dist/world-map-navigation.js +53 -0
  144. package/dist/world-map-pan.d.ts +3 -0
  145. package/dist/world-map-pan.d.ts.map +1 -0
  146. package/dist/world-map-pan.js +66 -0
  147. package/dist/world-map-zoom.d.ts +13 -0
  148. package/dist/world-map-zoom.d.ts.map +1 -0
  149. package/dist/world-map-zoom.js +61 -0
  150. package/dist/world-map.d.ts +71 -0
  151. package/dist/world-map.d.ts.map +1 -0
  152. package/dist/world-map.js +143 -0
  153. package/package.json +51 -4
@@ -0,0 +1,95 @@
1
+ import { type LumenChartDomain, type LumenChartTone } from './charts.js';
2
+ export interface LumenCalendarHeatmapDatum {
3
+ date: string;
4
+ value: number | null;
5
+ }
6
+ export interface LumenCalendarHeatmapOptions {
7
+ startDate: string;
8
+ endDate: string;
9
+ weekStartsOn?: 0 | 1 | undefined;
10
+ domain?: LumenChartDomain | undefined;
11
+ }
12
+ export interface LumenFunnelDatum {
13
+ id: string;
14
+ label: string;
15
+ value: number | null;
16
+ tone?: LumenChartTone;
17
+ }
18
+ export interface LumenBoxPlotDatum {
19
+ id: string;
20
+ label: string;
21
+ min: number | null;
22
+ q1: number | null;
23
+ median: number | null;
24
+ q3: number | null;
25
+ max: number | null;
26
+ outliers?: readonly number[];
27
+ tone?: LumenChartTone;
28
+ }
29
+ export interface LumenBoxPlotOptions {
30
+ domain?: LumenChartDomain | undefined;
31
+ }
32
+ export interface LumenBoxPlotStatisticLabels {
33
+ min: string;
34
+ q1: string;
35
+ median: string;
36
+ q3: string;
37
+ max: string;
38
+ outliers: string;
39
+ }
40
+ /** Strict Gregorian date-only identity, independent of locale, time zone and DST. */
41
+ export declare const parseLumenCalendarDate: (value: unknown) => number | null;
42
+ export declare const isLumenCalendarHeatmapDatum: (value: unknown) => value is LumenCalendarHeatmapDatum;
43
+ export declare const isLumenFunnelDatum: (value: unknown) => value is LumenFunnelDatum;
44
+ export declare const isLumenBoxPlotDatum: (value: unknown) => value is LumenBoxPlotDatum;
45
+ interface CalendarCell {
46
+ date: string;
47
+ value: number | null;
48
+ week: number;
49
+ day: number;
50
+ ratio: number | null;
51
+ }
52
+ export declare const createLumenCalendarHeatmapGeometry: (data: readonly LumenCalendarHeatmapDatum[], options: LumenCalendarHeatmapOptions) => {
53
+ valid: boolean;
54
+ domain: {
55
+ min: number;
56
+ max: number;
57
+ };
58
+ cells: CalendarCell[];
59
+ weekCount: number;
60
+ };
61
+ export declare const createLumenFunnelGeometry: (data: readonly LumenFunnelDatum[]) => {
62
+ valid: boolean;
63
+ max: number;
64
+ rows: {
65
+ ratio: number | null;
66
+ id: string;
67
+ label: string;
68
+ value: number | null;
69
+ tone?: LumenChartTone;
70
+ }[];
71
+ };
72
+ export declare const createLumenBoxPlotGeometry: (data: readonly LumenBoxPlotDatum[], options?: LumenBoxPlotOptions) => {
73
+ valid: boolean;
74
+ domain: LumenChartDomain;
75
+ ticks: number[];
76
+ rows: {
77
+ minPosition: number | null;
78
+ q1Position: number | null;
79
+ medianPosition: number | null;
80
+ q3Position: number | null;
81
+ maxPosition: number | null;
82
+ outlierPositions: number[];
83
+ id: string;
84
+ label: string;
85
+ min: number | null;
86
+ q1: number | null;
87
+ median: number | null;
88
+ q3: number | null;
89
+ max: number | null;
90
+ outliers?: readonly number[];
91
+ tone?: LumenChartTone;
92
+ }[];
93
+ };
94
+ export {};
95
+ //# sourceMappingURL=extended-charts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extended-charts.d.ts","sourceRoot":"","sources":["../src/extended-charts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAyC,MAAM,aAAa,CAAA;AAE/G,MAAM,WAAW,yBAAyB;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AACjF,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;IAChC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAA;CACtC;AACD,MAAM,WAAW,gBAAgB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,cAAc,CAAA;CAAE;AAC5G,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,IAAI,CAAC,EAAE,cAAc,CAAA;CACtB;AACD,MAAM,WAAW,mBAAmB;IAAG,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAA;CAAE;AAC9E,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;CACjB;AAQD,qFAAqF;AACrF,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,MAAM,GAAG,IAgBhE,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,yBAGrE,CAAA;AAOD,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAM5D,CAAA;AA8BD,eAAO,MAAM,mBAAmB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,iBAS7D,CAAA;AAgCD,UAAU,YAAY;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AAkD9G,eAAO,MAAM,kCAAkC,GAC7C,MAAM,SAAS,yBAAyB,EAAE,EAAE,SAAS,2BAA2B;;;;;;;;CAsBjF,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,MAAM,SAAS,gBAAgB,EAAE;;;;;YAjNnC,MAAM;eAAS,MAAM;eAAS,MAAM,GAAG,IAAI;eAAS,cAAc;;CAsOzG,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAI,MAAM,SAAS,iBAAiB,EAAE,EAAE,UAAS,mBAAwB;;;;;;;;;;;YAtO1G,MAAM;eACH,MAAM;aACR,MAAM,GAAG,IAAI;YACd,MAAM,GAAG,IAAI;gBACT,MAAM,GAAG,IAAI;YACjB,MAAM,GAAG,IAAI;aACZ,MAAM,GAAG,IAAI;mBACP,SAAS,MAAM,EAAE;eACrB,cAAc;;CAiQtB,CAAA"}
@@ -0,0 +1,175 @@
1
+ import { lumenChartTones, scaleLumenChartValue } from './charts.js';
2
+ const inRange = (value, min, max) => value >= min && value <= max;
3
+ const dayMilliseconds = 86_400_000;
4
+ const measurement = (value) => value === null || (typeof value === 'number' && Number.isFinite(value));
5
+ const text = (value) => typeof value === 'string' && value.trim().length > 0;
6
+ const tone = (value) => value === undefined || lumenChartTones.some(item => item === value);
7
+ /** Strict Gregorian date-only identity, independent of locale, time zone and DST. */
8
+ export const parseLumenCalendarDate = (value) => {
9
+ if (typeof value !== 'string' || value.length !== 10 || !/^\d{4}-\d{2}-\d{2}$/.test(value))
10
+ return null;
11
+ const year = Number(value.slice(0, 4));
12
+ const month = Number(value.slice(5, 7));
13
+ const day = Number(value.slice(8, 10));
14
+ if (year < 1 || !inRange(month, 1, 12) || !inRange(day, 1, 31))
15
+ return null;
16
+ const date = new Date(0);
17
+ date.setUTCFullYear(year, month - 1, day);
18
+ if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day)
19
+ return null;
20
+ return date.getTime();
21
+ };
22
+ export const isLumenCalendarHeatmapDatum = (value) => (typeof value === 'object' && value !== null && 'date' in value && 'value' in value &&
23
+ parseLumenCalendarDate(value.date) !== null && measurement(value.value));
24
+ const identityValid = (value) => (typeof value === 'object' && value !== null && 'id' in value && 'label' in value &&
25
+ text(value.id) && text(value.label) && (!('tone' in value) || tone(value.tone)));
26
+ export const isLumenFunnelDatum = (value) => {
27
+ if (!identityValid(value) || typeof value !== 'object' || value === null || !('value' in value))
28
+ return false;
29
+ if (!measurement(value.value))
30
+ return false;
31
+ return value.value === null || value.value >= 0;
32
+ };
33
+ const orderedStats = (stats) => stats.every((item, index) => {
34
+ const previous = stats[index - 1];
35
+ return typeof item === 'number' && Number.isFinite(item) &&
36
+ (index === 0 || (typeof previous === 'number' && item >= previous));
37
+ });
38
+ const validOutliers = (value, missing) => {
39
+ if (value === undefined)
40
+ return true;
41
+ if (!Array.isArray(value))
42
+ return false;
43
+ const entries = Array.from(value);
44
+ if (!entries.every(item => typeof item === 'number' && Number.isFinite(item)))
45
+ return false;
46
+ return !missing || value.length === 0;
47
+ };
48
+ const hasBoxStats = (value) => typeof value === 'object' && value !== null &&
49
+ 'min' in value && 'q1' in value && 'median' in value && 'q3' in value && 'max' in value;
50
+ export const isLumenBoxPlotDatum = (value) => {
51
+ if (!identityValid(value) || !hasBoxStats(value))
52
+ return false;
53
+ const stats = [value.min, value.q1, value.median, value.q3, value.max];
54
+ const missing = stats.every(item => item === null);
55
+ if (!missing && !orderedStats(stats))
56
+ return false;
57
+ return validOutliers('outliers' in value ? value.outliers : undefined, missing);
58
+ };
59
+ const automaticDomain = (values) => {
60
+ if (values.length === 0)
61
+ return { min: 0, max: 1 };
62
+ let min = values[0] ?? 0;
63
+ let max = min;
64
+ for (const value of values) {
65
+ min = Math.min(min, value);
66
+ max = Math.max(max, value);
67
+ }
68
+ if (min === max) {
69
+ const padding = Math.max(1, Math.abs(min) * 0.01);
70
+ const lower = min - padding;
71
+ const upper = max + padding;
72
+ min = Number.isFinite(lower) ? lower : min;
73
+ max = Number.isFinite(upper) ? upper : max;
74
+ }
75
+ return { min, max };
76
+ };
77
+ const validDomain = (domain, values) => (Number.isFinite(domain.min) && Number.isFinite(domain.max) && domain.min < domain.max &&
78
+ values.every(value => domain.min <= value && value <= domain.max));
79
+ const createCalendarCells = (start, count, weekStartsOn, dates, domain) => {
80
+ const cells = [];
81
+ const offset = (new Date(start).getUTCDay() - weekStartsOn + 7) % 7;
82
+ for (let index = 0; index < count; index++) {
83
+ const date = new Date(start + index * dayMilliseconds).toISOString().slice(0, 10);
84
+ const value = dates.get(date) ?? null;
85
+ cells.push({ date,
86
+ value,
87
+ week: Math.floor((offset + index) / 7),
88
+ day: (offset + index) % 7,
89
+ ratio: value === null ? null : scaleLumenChartValue(value, domain, 0, 1) });
90
+ }
91
+ return cells;
92
+ };
93
+ const calendarObservationInRange = (date, start, end) => {
94
+ const timestamp = parseLumenCalendarDate(date);
95
+ return timestamp !== null && inRange(timestamp, start, end);
96
+ };
97
+ const isArrayCollection = (value) => Array.isArray(value);
98
+ const calendarDates = (data, start, end) => {
99
+ const dates = new Map();
100
+ const valid = isArrayCollection(data) && Array.from(data).every(item => {
101
+ if (!isLumenCalendarHeatmapDatum(item) || dates.has(item.date))
102
+ return false;
103
+ if (!calendarObservationInRange(item.date, start, end))
104
+ return false;
105
+ dates.set(item.date, item.value);
106
+ return true;
107
+ });
108
+ return { valid, dates };
109
+ };
110
+ const isWeekStart = (value) => value === 0 || value === 1;
111
+ const invalidCalendar = () => ({ valid: false, domain: { min: 0, max: 1 }, cells: Array(), weekCount: 0 });
112
+ export const createLumenCalendarHeatmapGeometry = (data, options) => {
113
+ const start = parseLumenCalendarDate(options.startDate);
114
+ const end = parseLumenCalendarDate(options.endDate);
115
+ const weekStartsOn = options.weekStartsOn ?? 0;
116
+ if (start === null || end === null || !isWeekStart(weekStartsOn))
117
+ return invalidCalendar();
118
+ const count = (end - start) / dayMilliseconds + 1;
119
+ if (!inRange(count, 1, 3660))
120
+ return invalidCalendar();
121
+ const { valid: validData, dates } = calendarDates(data, start, end);
122
+ const values = [...dates.values()].filter((value) => value !== null);
123
+ const domain = options.domain ?? automaticDomain(values);
124
+ if (!validData || !validDomain(domain, values))
125
+ return invalidCalendar();
126
+ const cells = createCalendarCells(start, count, weekStartsOn, dates, domain);
127
+ const weekCount = Math.ceil(((new Date(start).getUTCDay() - weekStartsOn + 7) % 7 + count) / 7);
128
+ return { valid: true, domain, cells, weekCount };
129
+ };
130
+ export const createLumenFunnelGeometry = (data) => {
131
+ const ids = new Set();
132
+ let max = 0;
133
+ const valid = isArrayCollection(data) && Array.from(data).every(item => {
134
+ if (!isLumenFunnelDatum(item) || ids.has(item.id))
135
+ return false;
136
+ ids.add(item.id);
137
+ max = Math.max(max, item.value ?? 0);
138
+ return true;
139
+ });
140
+ const ratio = (value) => {
141
+ if (value === null)
142
+ return null;
143
+ return max === 0 ? 0 : value / max;
144
+ };
145
+ return { valid, max: valid ? max : 0, rows: valid ? data.map(item => ({ ...item, ratio: ratio(item.value) })) : [] };
146
+ };
147
+ export const createLumenBoxPlotGeometry = (data, options = {}) => {
148
+ const ids = new Set();
149
+ const validData = isArrayCollection(data) && Array.from(data).every(item => {
150
+ if (!isLumenBoxPlotDatum(item) || ids.has(item.id))
151
+ return false;
152
+ ids.add(item.id);
153
+ return true;
154
+ });
155
+ const values = validData ?
156
+ data.flatMap(item => ([item.min, item.q1, item.median, item.q3, item.max, ...(item.outliers ?? [])]
157
+ .filter((value) => value !== null))) :
158
+ [];
159
+ const requested = options.domain ?? automaticDomain(values);
160
+ const valid = validData && validDomain(requested, values);
161
+ const domain = valid ? requested : { min: 0, max: 1 };
162
+ const position = (value) => value === null ? null : scaleLumenChartValue(value, domain, 0, 1);
163
+ return { valid,
164
+ domain,
165
+ ticks: [domain.min, domain.min / 2 + domain.max / 2, domain.max],
166
+ rows: valid ?
167
+ data.map(item => ({ ...item,
168
+ minPosition: position(item.min),
169
+ q1Position: position(item.q1),
170
+ medianPosition: position(item.median),
171
+ q3Position: position(item.q3),
172
+ maxPosition: position(item.max),
173
+ outlierPositions: (item.outliers ?? []).map(value => scaleLumenChartValue(value, domain, 0, 1)) })) :
174
+ [] };
175
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"figma.d.ts","sourceRoot":"","sources":["../src/figma.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EAEvB,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAOnB,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,oBAAoB,CAAA;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,kBAAkB,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,sBAAsB,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,+BAA+B;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,MAAM,oBAAoB,GAC5B,OAAO,GACT,aAAa,GACb,WAAW,GACX,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,QAAQ,CAAA;AAEV,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,yBAAyB,EAAE,sBAAsB,CAAC,CAAC,CAAA;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,uBAAuB,EAAE,yBAAyB,CAAC,CAAC,CAAA;CAChF;AAyGD,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,oBAUpD,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MAMlD,CAAA;AAED,eAAO,MAAM,uBAAuB,GAClC,OAAO,mBAAmB,EAC1B,eAAgB,KACf,MAAmD,CAAA;AAEtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,gBAAgB,EACxB,UAAS,+BAAoC,KAC5C,4BAwBF,CAAA;AAuCD,eAAO,MAAM,uBAAuB,GAClC,QAAQ,gBAAgB,KACvB,sBAyCD,CAAA"}
1
+ {"version":3,"file":"figma.d.ts","sourceRoot":"","sources":["../src/figma.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EAEvB,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAOnB,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,oBAAoB,CAAA;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,kBAAkB,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,sBAAsB,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,+BAA+B;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,MAAM,oBAAoB,GAC5B,OAAO,GACT,aAAa,GACb,WAAW,GACX,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,QAAQ,CAAA;AAEV,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,yBAAyB,EAAE,sBAAsB,CAAC,CAAC,CAAA;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,uBAAuB,EAAE,yBAAyB,CAAC,CAAC,CAAA;CAChF;AAkHD,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,oBAUpD,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MAMlD,CAAA;AAED,eAAO,MAAM,uBAAuB,GAClC,OAAO,mBAAmB,EAC1B,eAAgB,KACf,MAAmD,CAAA;AAEtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,gBAAgB,EACxB,UAAS,+BAAoC,KAC5C,4BAwBF,CAAA;AAuCD,eAAO,MAAM,uBAAuB,GAClC,QAAQ,gBAAgB,KACvB,sBAyCD,CAAA"}
package/dist/figma.js CHANGED
@@ -30,6 +30,15 @@ const lumenTokenDescriptions = {
30
30
  'surface-muted': 'Subtle component surface.',
31
31
  'surface-strong': 'Raised or stronger component surface.',
32
32
  'ui-duration': 'Base transition duration for interactive states.',
33
+ 'ui-border-width': 'Structural border width; focus indicators remain independent.',
34
+ 'ui-space-zero': 'Zero spacing.',
35
+ 'ui-space-xs': 'Extra small spacing.',
36
+ 'ui-space-sm': 'Small spacing.',
37
+ 'ui-space-md': 'Medium spacing.',
38
+ 'ui-space-lg': 'Large spacing.',
39
+ 'ui-space-xl': 'Extra large spacing.',
40
+ 'ui-space-2xl': 'Section spacing.',
41
+ 'ui-space-3xl': 'Large section spacing.',
33
42
  'ui-duration-fast': 'Fast transition duration for small state changes.',
34
43
  'ui-duration-slow': 'Slow transition duration for larger movements.',
35
44
  'ui-ease': 'Standard easing curve for interface motion.',
@@ -149,7 +158,7 @@ const getEffectDesignTokenValue = (token, value) => {
149
158
  const getStructureDesignTokenType = (token) => {
150
159
  if (token === 'ui-font')
151
160
  return 'fontFamily';
152
- if (token.startsWith('ui-radius'))
161
+ if (token.startsWith('ui-radius') || token.startsWith('ui-space') || token === 'ui-border-width')
153
162
  return 'dimension';
154
163
  if (token.startsWith('ui-shadow'))
155
164
  return 'shadow';
@@ -0,0 +1,24 @@
1
+ export type LumenFloatingPanelPlacement = 'bottom-end' | 'bottom-start' | 'top-end' | 'top-start';
2
+ export interface LumenFloatingPanelOptions {
3
+ /** Logical alignment follows the trigger's inherited text direction. */
4
+ placement?: LumenFloatingPanelPlacement | undefined;
5
+ offset?: number | undefined;
6
+ collisionPadding?: number | undefined;
7
+ /** Focus the first matching element inside the panel after it opens. A malformed selector skips focus. */
8
+ initialFocus?: string | undefined;
9
+ /**
10
+ * Called when the panel should close: focus moves outside, its containing dialog closes, or the trigger
11
+ * or panel leaves the document. The caller hides the panel and calls the cleanup.
12
+ */
13
+ onDismiss: () => void;
14
+ }
15
+ /**
16
+ * Shows `panel` anchored to `trigger`: in the top layer when the Popover API exists, otherwise fixed. The
17
+ * panel follows scroll, resize, visual viewport, and enclosing animation changes, flips to stay visible,
18
+ * honors RTL, and calls `onDismiss` on outside focus, when its containing dialog closes, or when the trigger
19
+ * or panel leaves the document. Connecting makes the panel visible; the caller owns hiding it again. The returned
20
+ * cleanup leaves the top layer, returns owned focus to the trigger, restores the panel's previous inline
21
+ * styles and popover attributes, and removes every listener and observer.
22
+ */
23
+ export declare const connectLumenFloatingPanel: (panel: HTMLElement, trigger: HTMLElement, { placement, offset, collisionPadding, initialFocus, onDismiss }: LumenFloatingPanelOptions) => (() => void);
24
+ //# sourceMappingURL=floating-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating-panel.d.ts","sourceRoot":"","sources":["../src/floating-panel.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,2BAA2B,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,CAAA;AAEjG,MAAM,WAAW,yBAAyB;IACxC,wEAAwE;IACxE,SAAS,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAA;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,0GAA0G;IAC1G,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC;;;OAGG;IACH,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB;AA4MD;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,WAAW,EAClB,SAAS,WAAW,EACpB,kEAAmF,yBAAyB,KAC3G,CAAC,MAAM,IAAI,CA8Db,CAAA"}
@@ -0,0 +1,203 @@
1
+ const finiteDistance = (value, fallback) => {
2
+ if (value === undefined || !Number.isFinite(value))
3
+ return fallback;
4
+ return Math.max(0, value);
5
+ };
6
+ const clamp = (value, minimum, maximum) => {
7
+ const upperBound = Math.max(minimum, maximum);
8
+ return Math.max(minimum, Math.min(value, upperBound));
9
+ };
10
+ const styleKeys = [
11
+ 'box-sizing',
12
+ 'position',
13
+ 'inset',
14
+ 'left',
15
+ 'top',
16
+ 'right',
17
+ 'bottom',
18
+ 'margin',
19
+ 'max-width',
20
+ 'max-height',
21
+ 'overflow-y'
22
+ ];
23
+ const viewportBounds = ({ view, padding }) => {
24
+ const viewport = view.visualViewport;
25
+ const left = (viewport?.offsetLeft ?? 0) + padding;
26
+ const top = (viewport?.offsetTop ?? 0) + padding;
27
+ const width = Math.max(0, (viewport?.width ?? view.innerWidth) - padding * 2);
28
+ const height = Math.max(0, (viewport?.height ?? view.innerHeight) - padding * 2);
29
+ return { left, top, width, height, right: left + width, bottom: top + height };
30
+ };
31
+ const shouldPlaceBelow = (placement, above, below, height) => placement.startsWith('bottom') ? below >= height || below >= above : !(above >= height || above >= below);
32
+ const positionPanel = (context) => {
33
+ const { panel, trigger, view, placement, gap } = context;
34
+ const viewport = viewportBounds(context);
35
+ const anchor = trigger.getBoundingClientRect();
36
+ panel.style.boxSizing = 'border-box';
37
+ panel.style.position = 'fixed';
38
+ panel.style.inset = 'auto';
39
+ panel.style.margin = '0';
40
+ panel.style.maxWidth = `${viewport.width}px`;
41
+ panel.style.maxHeight = `${viewport.height}px`;
42
+ panel.style.overflowY = 'auto';
43
+ const below = Math.max(0, viewport.bottom - anchor.bottom - gap);
44
+ const above = Math.max(0, anchor.top - viewport.top - gap);
45
+ const placeBelow = shouldPlaceBelow(placement, above, below, panel.getBoundingClientRect().height);
46
+ const availableHeight = placeBelow ? below : above;
47
+ panel.style.maxHeight = `${Math.min(viewport.height, availableHeight || viewport.height)}px`;
48
+ const bounds = panel.getBoundingClientRect();
49
+ const rtl = view.getComputedStyle(trigger).direction === 'rtl';
50
+ const alignRight = placement.endsWith('end') !== rtl;
51
+ const x = alignRight ? anchor.right - bounds.width : anchor.left;
52
+ const y = placeBelow ? anchor.bottom + gap : anchor.top - bounds.height - gap;
53
+ const alignment = placement.endsWith('end') ? 'end' : 'start';
54
+ panel.style.left = `${clamp(x, viewport.left, viewport.right - bounds.width)}px`;
55
+ panel.style.top = `${clamp(y, viewport.top, viewport.bottom - bounds.height)}px`;
56
+ panel.dataset.placement = `${placeBelow ? 'bottom' : 'top'}-${alignment}`;
57
+ };
58
+ // Transform transitions and animations move the trigger without resizing it, so ResizeObserver stays quiet.
59
+ const settleEvents = ['animationend', 'animationcancel', 'transitionend', 'transitioncancel'];
60
+ const observePosition = (context, dismiss) => {
61
+ const { panel, trigger, view } = context;
62
+ const document = panel.ownerDocument;
63
+ const NodeType = view.Node;
64
+ const dialog = trigger.closest('dialog');
65
+ const position = () => {
66
+ positionPanel(context);
67
+ };
68
+ const focusOutside = (event) => {
69
+ if (event.target instanceof NodeType &&
70
+ !panel.contains(event.target) && !trigger.contains(event.target))
71
+ dismiss();
72
+ };
73
+ const scroll = (event) => {
74
+ if (!(event.target instanceof NodeType) || !panel.contains(event.target))
75
+ position();
76
+ };
77
+ const observer = typeof view.ResizeObserver === 'function' ? new view.ResizeObserver(position) : undefined;
78
+ // Removing an open panel's owner must not leave document listeners or an expanded trigger behind.
79
+ const removal = typeof view.MutationObserver === 'function' ?
80
+ new view.MutationObserver(() => {
81
+ if (!trigger.isConnected || !panel.isConnected ||
82
+ trigger.ownerDocument !== document || panel.ownerDocument !== document)
83
+ dismiss();
84
+ }) :
85
+ undefined;
86
+ removal?.observe(document, { childList: true, subtree: true });
87
+ observer?.observe(trigger);
88
+ observer?.observe(panel);
89
+ document.addEventListener('focusin', focusOutside);
90
+ document.addEventListener('scroll', scroll, true);
91
+ for (const type of settleEvents)
92
+ document.addEventListener(type, position, true);
93
+ // Some engines move focus to the body without a focusin when a containing dialog closes.
94
+ dialog?.addEventListener('close', dismiss);
95
+ view.addEventListener('resize', position);
96
+ view.visualViewport?.addEventListener('resize', position);
97
+ view.visualViewport?.addEventListener('scroll', position);
98
+ return () => {
99
+ observer?.disconnect();
100
+ removal?.disconnect();
101
+ document.removeEventListener('focusin', focusOutside);
102
+ document.removeEventListener('scroll', scroll, true);
103
+ for (const type of settleEvents)
104
+ document.removeEventListener(type, position, true);
105
+ dialog?.removeEventListener('close', dismiss);
106
+ view.removeEventListener('resize', position);
107
+ view.visualViewport?.removeEventListener('resize', position);
108
+ view.visualViewport?.removeEventListener('scroll', position);
109
+ };
110
+ };
111
+ const restoreExternalFocus = (owner, focused) => {
112
+ const ElementType = owner.defaultView?.HTMLElement;
113
+ if (ElementType && focused instanceof ElementType && focused.isConnected && owner.activeElement !== focused) {
114
+ focused.focus({ preventScroll: true });
115
+ }
116
+ };
117
+ const restoreFocus = (panel, trigger, topLayer) => {
118
+ const document = panel.ownerDocument;
119
+ const focused = document.activeElement;
120
+ const ownedFocus = focused !== null && panel.contains(focused);
121
+ if (topLayer && panel.matches(':popover-open'))
122
+ panel.hidePopover();
123
+ if (ownedFocus && trigger.isConnected)
124
+ trigger.focus({ preventScroll: true });
125
+ // Closing a panel must not steal focus from a dialog opened by its action.
126
+ if (!ownedFocus)
127
+ restoreExternalFocus(document, focused);
128
+ };
129
+ const restoreAttribute = (panel, name, value) => {
130
+ if (value === null)
131
+ panel.removeAttribute(name);
132
+ else
133
+ panel.setAttribute(name, value);
134
+ };
135
+ // A malformed selector must not abort after the panel is shown, so it is resolved first and only skips focus.
136
+ const findInitialFocus = (panel, view, selector) => {
137
+ if (!selector)
138
+ return null;
139
+ try {
140
+ return panel.querySelector(selector);
141
+ }
142
+ catch (error) {
143
+ if (error instanceof view.DOMException && error.name === 'SyntaxError')
144
+ return null;
145
+ throw error;
146
+ }
147
+ };
148
+ /**
149
+ * Shows `panel` anchored to `trigger`: in the top layer when the Popover API exists, otherwise fixed. The
150
+ * panel follows scroll, resize, visual viewport, and enclosing animation changes, flips to stay visible,
151
+ * honors RTL, and calls `onDismiss` on outside focus, when its containing dialog closes, or when the trigger
152
+ * or panel leaves the document. Connecting makes the panel visible; the caller owns hiding it again. The returned
153
+ * cleanup leaves the top layer, returns owned focus to the trigger, restores the panel's previous inline
154
+ * styles and popover attributes, and removes every listener and observer.
155
+ */
156
+ export const connectLumenFloatingPanel = (panel, trigger, { placement = 'bottom-start', offset, collisionPadding, initialFocus, onDismiss }) => {
157
+ const view = panel.ownerDocument.defaultView;
158
+ if (!view)
159
+ return () => undefined;
160
+ const context = {
161
+ panel,
162
+ trigger,
163
+ view,
164
+ placement,
165
+ gap: finiteDistance(offset, 6),
166
+ padding: finiteDistance(collisionPadding, 8)
167
+ };
168
+ const focusTarget = findInitialFocus(panel, view, initialFocus);
169
+ const previousPopover = panel.getAttribute('popover');
170
+ const previousPlacement = panel.getAttribute('data-placement');
171
+ const previousStyles = styleKeys.map(key => [
172
+ key, panel.style.getPropertyValue(key), panel.style.getPropertyPriority(key)
173
+ ]);
174
+ const topLayer = typeof panel.showPopover === 'function';
175
+ panel.hidden = false;
176
+ if (topLayer) {
177
+ panel.setAttribute('popover', 'manual');
178
+ panel.showPopover();
179
+ }
180
+ positionPanel(context);
181
+ focusTarget?.focus({ preventScroll: true });
182
+ let connected = true;
183
+ const dismiss = () => {
184
+ if (connected)
185
+ onDismiss();
186
+ };
187
+ const stopObserving = observePosition(context, dismiss);
188
+ return () => {
189
+ if (!connected)
190
+ return;
191
+ connected = false;
192
+ stopObserving();
193
+ restoreFocus(panel, trigger, topLayer);
194
+ restoreAttribute(panel, 'popover', previousPopover);
195
+ restoreAttribute(panel, 'data-placement', previousPlacement);
196
+ for (const [key, value, priority] of previousStyles) {
197
+ if (value)
198
+ panel.style.setProperty(key, value, priority);
199
+ else
200
+ panel.style.removeProperty(key);
201
+ }
202
+ };
203
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../src/forms.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,mEAMpB,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;AAE9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO;IAC9C,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,OAAO,EAAE,IAAI,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,KAAK,CAAA;CACf;AAED,MAAM,MAAM,eAAe,CAAC,IAAI,GAAG,OAAO,IAAI,gBAAgB,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;AAEvF,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACjB,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAC7D,SAAS,eAAe,EAAE,GAC1B,IAAI,GACJ,SAAS,CAAA;AAiDX,eAAO,MAAM,wBAAwB,GACnC,OAAO,mBAAmB,KACzB,eAqCF,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,eAAe,EACvB,MAAM,MAAM,KACX,eAAe,EAAwD,CAAA;AAE1E,eAAO,MAAM,sBAAsB,GAAI,IAAI,EACzC,MAAM,IAAI,KACT,gBAAgB,CAAC,IAAI,CAA8B,CAAA;AAEtD,eAAO,MAAM,sBAAsB,GACjC,QAAQ,mBAAmB,KAC1B,gBAGD,CAAA"}
1
+ {"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../src/forms.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,mEAMpB,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;AAE9D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO;IAC9C,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,OAAO,EAAE,IAAI,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,KAAK,CAAA;CACf;AAED,MAAM,MAAM,eAAe,CAAC,IAAI,GAAG,OAAO,IAAI,gBAAgB,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;AAEvF,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACjB,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAC7D,SAAS,eAAe,EAAE,GAC1B,IAAI,GACJ,SAAS,CAAA;AAiEX,eAAO,MAAM,wBAAwB,GACnC,OAAO,mBAAmB,KACzB,eAqCF,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,eAAe,EACvB,MAAM,MAAM,KACX,eAAe,EAAwD,CAAA;AAE1E,eAAO,MAAM,sBAAsB,GAAI,IAAI,EACzC,MAAM,IAAI,KACT,gBAAgB,CAAC,IAAI,CAA8B,CAAA;AAEtD,eAAO,MAAM,sBAAsB,GACjC,QAAQ,mBAAmB,KAC1B,gBAGD,CAAA"}
package/dist/forms.js CHANGED
@@ -5,8 +5,21 @@ export const lumenFormStatuses = [
5
5
  'success',
6
6
  'error'
7
7
  ];
8
- const isStringArray = (value) => Array.isArray(value);
9
- const isLumenFieldErrorArray = (value) => Array.isArray(value);
8
+ const isStringArray = (value) => Array.isArray(value) &&
9
+ value.every((message) => typeof message === 'string');
10
+ const isOptionalString = (value) => value === undefined || typeof value === 'string';
11
+ const isLumenFieldError = (value) => {
12
+ if (typeof value !== 'object' || value === null)
13
+ return false;
14
+ if (!('message' in value) || typeof value.message !== 'string')
15
+ return false;
16
+ if (!('name' in value) || typeof value.name !== 'string')
17
+ return false;
18
+ if ('code' in value && !isOptionalString(value.code))
19
+ return false;
20
+ return !('controlId' in value) || isOptionalString(value.controlId);
21
+ };
22
+ const isLumenFieldErrorArray = (value) => Array.isArray(value) && value.every(isLumenFieldError);
10
23
  const compactMessages = (value) => {
11
24
  if (typeof value === 'string') {
12
25
  const message = value.trim();
@@ -21,9 +34,10 @@ const compactMessages = (value) => {
21
34
  const isLumenFormErrors = (value) => Boolean(value &&
22
35
  !Array.isArray(value) &&
23
36
  'fields' in value &&
24
- Array.isArray(value.fields) &&
37
+ isLumenFieldErrorArray(value.fields) &&
25
38
  'form' in value &&
26
- Array.isArray(value.form));
39
+ isStringArray(value.form) &&
40
+ (value.fields.length > 0 || Object.keys(value).every(name => name === 'fields' || name === 'form')));
27
41
  const normalizeFieldError = (error) => {
28
42
  const message = error.message.trim();
29
43
  const name = error.name.trim();