@pdfme/schemas 5.0.0 → 5.1.1-dev.1

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 (53) hide show
  1. package/dist/cjs/src/date/date.js +54 -0
  2. package/dist/cjs/src/date/date.js.map +1 -0
  3. package/dist/cjs/src/date/dateTime.js +96 -0
  4. package/dist/cjs/src/date/dateTime.js.map +1 -0
  5. package/dist/cjs/src/date/helper.js +232 -0
  6. package/dist/cjs/src/date/helper.js.map +1 -0
  7. package/dist/cjs/src/date/time.js +25 -0
  8. package/dist/cjs/src/date/time.js.map +1 -0
  9. package/dist/cjs/src/date/types.js +3 -0
  10. package/dist/cjs/src/date/types.js.map +1 -0
  11. package/dist/cjs/src/index.js +9 -1
  12. package/dist/cjs/src/index.js.map +1 -1
  13. package/dist/cjs/src/select/index.js +162 -0
  14. package/dist/cjs/src/select/index.js.map +1 -0
  15. package/dist/cjs/src/text/extraFormatter.js.map +1 -1
  16. package/dist/cjs/src/text/uiRender.js +6 -4
  17. package/dist/cjs/src/text/uiRender.js.map +1 -1
  18. package/dist/esm/src/date/date.js +52 -0
  19. package/dist/esm/src/date/date.js.map +1 -0
  20. package/dist/esm/src/date/dateTime.js +94 -0
  21. package/dist/esm/src/date/dateTime.js.map +1 -0
  22. package/dist/esm/src/date/helper.js +225 -0
  23. package/dist/esm/src/date/helper.js.map +1 -0
  24. package/dist/esm/src/date/time.js +23 -0
  25. package/dist/esm/src/date/time.js.map +1 -0
  26. package/dist/esm/src/date/types.js +2 -0
  27. package/dist/esm/src/date/types.js.map +1 -0
  28. package/dist/esm/src/index.js +5 -1
  29. package/dist/esm/src/index.js.map +1 -1
  30. package/dist/esm/src/select/index.js +157 -0
  31. package/dist/esm/src/select/index.js.map +1 -0
  32. package/dist/esm/src/text/extraFormatter.js.map +1 -1
  33. package/dist/esm/src/text/uiRender.js +3 -3
  34. package/dist/esm/src/text/uiRender.js.map +1 -1
  35. package/dist/types/src/date/date.d.ts +2 -0
  36. package/dist/types/src/date/dateTime.d.ts +2 -0
  37. package/dist/types/src/date/helper.d.ts +9 -0
  38. package/dist/types/src/date/time.d.ts +2 -0
  39. package/dist/types/src/date/types.d.ts +11 -0
  40. package/dist/types/src/index.d.ts +5 -1
  41. package/dist/types/src/select/index.d.ts +7 -0
  42. package/dist/types/src/text/extraFormatter.d.ts +7 -2
  43. package/dist/types/src/text/uiRender.d.ts +4 -0
  44. package/package.json +3 -1
  45. package/src/date/date.ts +58 -0
  46. package/src/date/dateTime.ts +100 -0
  47. package/src/date/helper.ts +281 -0
  48. package/src/date/time.ts +29 -0
  49. package/src/date/types.ts +12 -0
  50. package/src/index.ts +8 -0
  51. package/src/select/index.ts +197 -0
  52. package/src/text/extraFormatter.ts +7 -4
  53. package/src/text/uiRender.ts +4 -4
@@ -0,0 +1,281 @@
1
+ import type * as CSS from 'csstype';
2
+ import AirDatepicker, { AirDatepickerLocale } from 'air-datepicker';
3
+ import localeEn from 'air-datepicker/locale/en';
4
+ import localeZh from 'air-datepicker/locale/zh';
5
+ import localeJa from 'air-datepicker/locale/ja';
6
+ import localeKo from 'air-datepicker/locale/ko';
7
+ import localeAr from 'air-datepicker/locale/ar';
8
+ import localeTh from 'air-datepicker/locale/th';
9
+ import localePl from 'air-datepicker/locale/pl';
10
+ import localeIt from 'air-datepicker/locale/it';
11
+ import localeDe from 'air-datepicker/locale/de';
12
+ import localeEs from 'air-datepicker/locale/es';
13
+ import localeFr from 'air-datepicker/locale/fr';
14
+ import 'air-datepicker/air-datepicker.css';
15
+ import { format } from 'date-fns';
16
+ import { enUS, zhCN, ja, ko, ar, th, pl, it, de, es, fr, Locale } from 'date-fns/locale';
17
+ import {
18
+ Lang,
19
+ Plugin,
20
+ getDefaultFont,
21
+ getFallbackFontName,
22
+ DEFAULT_FONT_NAME,
23
+ PropPanelSchema,
24
+ } from '@pdfme/common';
25
+ import text from '../text';
26
+ import { DEFAULT_OPACITY, HEX_COLOR_PATTERN } from '../constants.js';
27
+ import { mapVerticalAlignToFlex, getBackgroundColor } from '../text/uiRender';
28
+ import { getFontKitFont, getBrowserVerticalFontAdjustments } from '../text/helper.js';
29
+ import {
30
+ DEFAULT_FONT_SIZE,
31
+ DEFAULT_ALIGNMENT,
32
+ VERTICAL_ALIGN_MIDDLE,
33
+ DEFAULT_LINE_HEIGHT,
34
+ DEFAULT_CHARACTER_SPACING,
35
+ DEFAULT_FONT_COLOR,
36
+ } from '../text/constants.js';
37
+ import { DateSchema } from './types';
38
+ import { getExtraFormatterSchema, Formatter } from '../text/extraFormatter';
39
+ import { isEditable } from '../utils';
40
+
41
+ const getDateFnsLocale = (lang: Lang): Locale | undefined =>
42
+ ({ en: enUS, zh: zhCN, ja, ko, ar, th, pl, it, de, es, fr }[lang]);
43
+
44
+ const getAirDatepickerLocale = (lang: Lang): AirDatepickerLocale | undefined =>
45
+ ({
46
+ en: localeEn,
47
+ zh: localeZh,
48
+ ja: localeJa,
49
+ ko: localeKo,
50
+ ar: localeAr,
51
+ th: localeTh,
52
+ pl: localePl,
53
+ it: localeIt,
54
+ de: localeDe,
55
+ es: localeEs,
56
+ fr: localeFr,
57
+ }[lang]);
58
+
59
+ export const getPlugin = ({
60
+ type,
61
+ defaultFormat,
62
+ icon,
63
+ formatsByLang,
64
+ }: {
65
+ type: 'date' | 'time' | 'dateTime';
66
+ defaultFormat: string;
67
+ icon: string;
68
+ formatsByLang: Record<Lang, string[]>;
69
+ }) => {
70
+ const plugin: Plugin<DateSchema> = {
71
+ ui: async (arg) => {
72
+ const { schema, value, onChange, rootElement, mode, options, i18n, _cache } = arg;
73
+
74
+ const beforeRemoveEvent = new Event('beforeRemove');
75
+ rootElement.dispatchEvent(beforeRemoveEvent);
76
+
77
+ const font = options?.font || getDefaultFont();
78
+ const fontKitFont = await getFontKitFont(schema.fontName, font, _cache);
79
+
80
+ const { topAdj, bottomAdj } = getBrowserVerticalFontAdjustments(
81
+ fontKitFont,
82
+ schema.fontSize ?? DEFAULT_FONT_SIZE,
83
+ DEFAULT_LINE_HEIGHT,
84
+ VERTICAL_ALIGN_MIDDLE
85
+ );
86
+
87
+ const topAdjustment = topAdj.toString();
88
+ const bottomAdjustment = bottomAdj.toString();
89
+ const textStyle: CSS.Properties = {
90
+ fontFamily: schema.fontName ? `'${schema.fontName}'` : 'inherit',
91
+ color: schema.fontColor ?? DEFAULT_FONT_COLOR,
92
+ fontSize: `${schema.fontSize ?? DEFAULT_FONT_SIZE}pt`,
93
+ letterSpacing: `${schema.characterSpacing ?? DEFAULT_CHARACTER_SPACING}pt`,
94
+ textAlign: schema.alignment ?? DEFAULT_ALIGNMENT,
95
+ backgroundColor: getBackgroundColor(value, schema),
96
+
97
+ margin: '0',
98
+ padding: '0',
99
+ border: 'none',
100
+ outline: 'none',
101
+ width: `${schema.width}mm`,
102
+ height: `${schema.height}mm`,
103
+ display: 'flex',
104
+ flexDirection: 'column',
105
+ justifyContent: mapVerticalAlignToFlex(VERTICAL_ALIGN_MIDDLE),
106
+ paddingTop: `${topAdjustment}px`,
107
+ marginBottom: `${bottomAdjustment}px`,
108
+ position: 'relative',
109
+ };
110
+
111
+ const input = document.createElement('input');
112
+
113
+ Object.assign(input.style, textStyle);
114
+
115
+ const commitChange = ({ datepicker }: { datepicker: AirDatepicker<HTMLInputElement> }) => {
116
+ if (onChange) {
117
+ const date = datepicker.selectedDates;
118
+ const fmt =
119
+ type === 'time' ? 'HH:mm' : type === 'date' ? 'yyyy/MM/dd' : 'yyyy/MM/dd HH:mm';
120
+ const d = Array.isArray(date) ? date[0] : date || '';
121
+ const value = d ? format(d, fmt) : '';
122
+ onChange({ key: 'content', value });
123
+ }
124
+ };
125
+
126
+ const airDatepicker = new AirDatepicker(input, {
127
+ locale: getAirDatepickerLocale(options.lang || 'en'),
128
+ selectedDates: [schema.type === 'time' ? new Date(`2021-01-01T${value}`) : new Date(value)],
129
+ dateFormat: (date) => (schema.format ? format(date, schema.format) : ''),
130
+ timepicker: type !== 'date',
131
+ onlyTimepicker: type === 'time',
132
+ buttons: [
133
+ 'clear',
134
+ {
135
+ content: i18n('close'),
136
+ onClick: (datepicker) => {
137
+ datepicker.hide();
138
+ commitChange({ datepicker });
139
+ },
140
+ },
141
+ ],
142
+ onSelect: ({ datepicker }) => {
143
+ mode !== 'designer' && commitChange({ datepicker });
144
+ },
145
+ onShow: () => {
146
+ input.disabled = !isEditable(mode, schema);
147
+ },
148
+ });
149
+
150
+ rootElement.addEventListener('beforeRemove', () => {
151
+ if (mode === 'designer') {
152
+ airDatepicker.destroy();
153
+ }
154
+ });
155
+ input.addEventListener('click', () => {
156
+ if (mode === 'designer') {
157
+ airDatepicker.show();
158
+ }
159
+ });
160
+
161
+ rootElement.appendChild(input);
162
+ },
163
+ pdf: (arg) => {
164
+ const { schema, value, options } = arg;
165
+ if (!value) return void 0;
166
+ const lang = (options.lang || 'en') as Lang;
167
+ const locale = getDateFnsLocale(lang);
168
+ const date = schema.type === 'time' ? new Date(`2021-01-01T${value}`) : new Date(value);
169
+ const formattedValue = format(date, schema.format, { locale });
170
+ return text.pdf(
171
+ Object.assign(arg, {
172
+ value: formattedValue,
173
+ schema: {
174
+ ...schema,
175
+ verticalAlignment: VERTICAL_ALIGN_MIDDLE,
176
+ lineHeight: DEFAULT_LINE_HEIGHT,
177
+ },
178
+ })
179
+ );
180
+ },
181
+ propPanel: {
182
+ schema: ({ options, i18n }) => {
183
+ const font = options.font || { [DEFAULT_FONT_NAME]: { data: '', fallback: true } };
184
+ const lang = options.lang || 'en';
185
+ const locale = getDateFnsLocale(lang);
186
+
187
+ const fontNames = Object.keys(font);
188
+ const fallbackFontName = getFallbackFontName(font);
189
+
190
+ const formatter = getExtraFormatterSchema(i18n);
191
+ formatter.buttons = formatter.buttons.filter(
192
+ (button) => button.key === Formatter.ALIGNMENT
193
+ );
194
+
195
+ const currentDate = new Date();
196
+
197
+ const dateSchema: Record<string, PropPanelSchema> = {
198
+ format: {
199
+ title: i18n('schemas.date.format'),
200
+ type: 'string',
201
+ widget: 'select',
202
+ props: {
203
+ options: formatsByLang[lang].map((formatString) => ({
204
+ label: `${formatString} (${format(currentDate, formatString, { locale })})`,
205
+ value: formatString,
206
+ })),
207
+ },
208
+ span: 24,
209
+ },
210
+ fontName: {
211
+ title: i18n('schemas.text.fontName'),
212
+ type: 'string',
213
+ widget: 'select',
214
+ default: fallbackFontName,
215
+ props: { options: fontNames.map((name) => ({ label: name, value: name })) },
216
+ span: 12,
217
+ },
218
+ fontSize: {
219
+ title: i18n('schemas.text.size'),
220
+ type: 'number',
221
+ widget: 'inputNumber',
222
+ span: 6,
223
+ props: { min: 0 },
224
+ },
225
+ characterSpacing: {
226
+ title: i18n('schemas.text.spacing'),
227
+ type: 'number',
228
+ widget: 'inputNumber',
229
+ span: 6,
230
+ props: { min: 0 },
231
+ },
232
+ formatter,
233
+ fontColor: {
234
+ title: i18n('schemas.textColor'),
235
+ type: 'string',
236
+ widget: 'color',
237
+ rules: [
238
+ {
239
+ pattern: HEX_COLOR_PATTERN,
240
+ message: i18n('validation.hexColor'),
241
+ },
242
+ ],
243
+ },
244
+ backgroundColor: {
245
+ title: i18n('schemas.bgColor'),
246
+ type: 'string',
247
+ widget: 'color',
248
+ rules: [
249
+ {
250
+ pattern: HEX_COLOR_PATTERN,
251
+ message: i18n('validation.hexColor'),
252
+ },
253
+ ],
254
+ },
255
+ };
256
+
257
+ return dateSchema;
258
+ },
259
+ defaultSchema: {
260
+ name: '',
261
+ format: defaultFormat,
262
+ type,
263
+ content: format(new Date(), defaultFormat),
264
+ position: { x: 0, y: 0 },
265
+ width: 70,
266
+ height: 10,
267
+ rotate: 0,
268
+ alignment: DEFAULT_ALIGNMENT,
269
+ fontSize: DEFAULT_FONT_SIZE,
270
+ characterSpacing: DEFAULT_CHARACTER_SPACING,
271
+ fontColor: DEFAULT_FONT_COLOR,
272
+ fontName: undefined,
273
+ backgroundColor: '',
274
+ opacity: DEFAULT_OPACITY,
275
+ },
276
+ },
277
+ icon,
278
+ };
279
+
280
+ return plugin;
281
+ };
@@ -0,0 +1,29 @@
1
+ import { Lang } from '@pdfme/common';
2
+ import { getPlugin } from './helper';
3
+
4
+ const type = 'time';
5
+
6
+ const defaultFormat = 'HH:mm';
7
+
8
+ const formatsByLang: Record<Lang, string[]> = {
9
+ en: [defaultFormat, 'hh:mm a', 'HH:mm:ss', 'hh:mm:ss a'],
10
+ zh: [defaultFormat, 'HH时mm分', 'HH:mm:ss'],
11
+ ja: [defaultFormat, 'HH時mm分', 'HH:mm:ss'],
12
+ ko: [defaultFormat, 'a h시 mm분', 'HH:mm:ss'],
13
+ ar: [defaultFormat, 'hh:mm a', 'HH:mm:ss'],
14
+ th: [defaultFormat, 'HH.mm', 'HH:mm:ss'],
15
+ pl: [defaultFormat, 'HH:mm:ss'],
16
+ it: [defaultFormat, 'HH.mm', 'HH:mm:ss'],
17
+ de: [defaultFormat, 'HH.mm', 'HH:mm:ss'],
18
+ es: [defaultFormat, 'hh:mm a', 'HH:mm:ss'],
19
+ fr: [defaultFormat, 'HH:mm:ss'],
20
+ };
21
+
22
+ const icon =
23
+ '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" ' +
24
+ 'viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
25
+ 'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ' +
26
+ 'class="lucide lucide-clock"><circle cx="12" cy="12" r="10"/>' +
27
+ '<polyline points="12 6 12 12 16 14"/></svg>';
28
+
29
+ export default getPlugin({ type, defaultFormat, icon, formatsByLang });
@@ -0,0 +1,12 @@
1
+ import { Schema } from '@pdfme/common';
2
+ import { ALIGNMENT } from '../text/types';
3
+
4
+ export interface DateSchema extends Schema {
5
+ format: string;
6
+ fontName?: string;
7
+ alignment: ALIGNMENT;
8
+ fontSize: number;
9
+ characterSpacing: number;
10
+ fontColor: string;
11
+ backgroundColor: string;
12
+ }
package/src/index.ts CHANGED
@@ -6,6 +6,10 @@ import barcodes from './barcodes/index.js';
6
6
  import line from './shapes/line.js';
7
7
  import table from './tables/index.js';
8
8
  import { rectangle, ellipse } from './shapes/rectAndEllipse.js';
9
+ import dateTime from './date/dateTime.js';
10
+ import date from './date/date.js';
11
+ import time from './date/time.js';
12
+ import select from './select/index.js';
9
13
 
10
14
  const builtInPlugins = { Text: text };
11
15
 
@@ -21,4 +25,8 @@ export {
21
25
  line,
22
26
  rectangle,
23
27
  ellipse,
28
+ dateTime,
29
+ date,
30
+ time,
31
+ select,
24
32
  };
@@ -0,0 +1,197 @@
1
+ import type * as CSS from 'csstype';
2
+ import { propPanel as parentPropPanel } from '../text/propPanel';
3
+ import { Plugin, PropPanelWidgetProps, SchemaForUI } from '@pdfme/common';
4
+ import text from '../text';
5
+ import { TextSchema } from '../text/types';
6
+
7
+ const selectIcon =
8
+ '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down"><path d="m6 9 6 6 6-6"/></svg>';
9
+
10
+ interface Select extends TextSchema {
11
+ options: string[];
12
+ }
13
+
14
+ const addOptions = (props: PropPanelWidgetProps) => {
15
+ const { rootElement, changeSchemas, activeSchema, i18n } = props;
16
+
17
+ rootElement.style.width = '100%';
18
+
19
+ const selectSchema = activeSchema as SchemaForUI & Select;
20
+ const currentOptions = selectSchema.options ? [...selectSchema.options] : [];
21
+
22
+ const inputStyle = {
23
+ width: '100%',
24
+ padding: '6.25px 11px',
25
+ border: '1px solid #ccc',
26
+ borderRadius: '4px',
27
+ };
28
+
29
+ const buttonStyle = { border: 'none', borderRadius: '4px', cursor: 'pointer' };
30
+
31
+ const updateSchemas = () => {
32
+ changeSchemas([
33
+ { key: 'options', value: currentOptions, schemaId: activeSchema.id },
34
+ { key: 'content', value: currentOptions[0] || '', schemaId: activeSchema.id },
35
+ ]);
36
+ };
37
+
38
+ const formContainer = document.createElement('div');
39
+ Object.assign(formContainer.style, {
40
+ width: '100%',
41
+ display: 'flex',
42
+ alignItems: 'center',
43
+ marginBottom: '10px',
44
+ });
45
+
46
+ const input = document.createElement('input');
47
+ input.type = 'text';
48
+ input.placeholder = i18n('schemas.select.optionPlaceholder');
49
+ Object.assign(input.style, inputStyle, { marginRight: '10px' });
50
+
51
+ const addButton = document.createElement('button');
52
+ addButton.textContent = '+';
53
+ Object.assign(addButton.style, buttonStyle, {
54
+ width: '25px',
55
+ height: '25px',
56
+ padding: '4px 8px',
57
+ });
58
+
59
+ addButton.addEventListener('click', () => {
60
+ const newValue = input.value.trim();
61
+ if (newValue) {
62
+ currentOptions.push(newValue);
63
+ updateSchemas();
64
+ renderOptions();
65
+ input.value = '';
66
+ }
67
+ });
68
+
69
+ formContainer.appendChild(input);
70
+ formContainer.appendChild(addButton);
71
+
72
+ const optionsList = document.createElement('ul');
73
+ Object.assign(optionsList.style, { listStyle: 'none', padding: '0' });
74
+
75
+ const renderOptions = () => {
76
+ optionsList.innerHTML = '';
77
+ currentOptions.forEach((option, index) => {
78
+ const li = document.createElement('li');
79
+ Object.assign(li.style, { display: 'flex', alignItems: 'center', marginBottom: '5px' });
80
+
81
+ const optionInput = document.createElement('input');
82
+ optionInput.type = 'text';
83
+ optionInput.value = option;
84
+ Object.assign(optionInput.style, inputStyle, { marginRight: '10px' });
85
+
86
+ optionInput.addEventListener('change', () => {
87
+ currentOptions[index] = optionInput.value;
88
+ updateSchemas();
89
+ });
90
+
91
+ const removeButton = document.createElement('button');
92
+ removeButton.textContent = 'x';
93
+ Object.assign(removeButton.style, buttonStyle, { padding: '4px 8px' });
94
+
95
+ removeButton.addEventListener('click', () => {
96
+ currentOptions.splice(index, 1);
97
+ updateSchemas();
98
+ renderOptions();
99
+ });
100
+
101
+ li.appendChild(optionInput);
102
+ li.appendChild(removeButton);
103
+ optionsList.appendChild(li);
104
+ });
105
+ };
106
+
107
+ rootElement.appendChild(formContainer);
108
+ rootElement.appendChild(optionsList);
109
+
110
+ renderOptions();
111
+ };
112
+
113
+ const schema: Plugin<Select> = {
114
+ ui: async (arg) => {
115
+ const { schema, value, onChange, rootElement, mode } = arg;
116
+ await text.ui(Object.assign(arg, { mode: 'viewer' }));
117
+
118
+ if (mode !== 'viewer' && !(mode === 'form' && schema.readOnly)) {
119
+ const buttonWidth = 30;
120
+ const selectButton = document.createElement('button');
121
+ selectButton.innerHTML = selectIcon;
122
+ const selectButtonStyle: CSS.Properties = {
123
+ position: 'absolute',
124
+ zIndex: -1,
125
+ right: `-${buttonWidth}px`,
126
+ top: '0',
127
+ padding: '0',
128
+ margin: '0',
129
+ cursor: 'pointer',
130
+ height: `${buttonWidth}px`,
131
+ width: `${buttonWidth}px`,
132
+ };
133
+ Object.assign(selectButton.style, selectButtonStyle);
134
+
135
+ rootElement.appendChild(selectButton);
136
+
137
+ const selectElement = document.createElement('select');
138
+ const selectElementStyle: CSS.Properties = {
139
+ opacity: '0',
140
+ position: 'absolute',
141
+ width: `calc(100% + ${buttonWidth}px)`,
142
+ height: '100%',
143
+ top: '0',
144
+ left: '0',
145
+ appearance: 'initial',
146
+ };
147
+ Object.assign(selectElement.style, selectElementStyle);
148
+ selectElement.value = value;
149
+
150
+ selectElement.addEventListener('change', (e) => {
151
+ if (onChange && e.target instanceof HTMLSelectElement) {
152
+ onChange && onChange({ key: 'content', value: e.target.value });
153
+ }
154
+ });
155
+
156
+ selectElement.innerHTML = schema.options
157
+ .map(
158
+ (option) =>
159
+ `<option value="${option}" ${option === value ? 'selected' : ''}>${option}</option>`
160
+ )
161
+ .join('');
162
+ rootElement.appendChild(selectElement);
163
+ }
164
+ },
165
+ pdf: text.pdf,
166
+ propPanel: {
167
+ ...text.propPanel,
168
+ widgets: { ...parentPropPanel.widgets, addOptions },
169
+ schema: (propPanelProps: Omit<PropPanelWidgetProps, 'rootElement'>) => {
170
+ if (typeof parentPropPanel.schema !== 'function') {
171
+ throw Error('Oops, is text schema no longer a function?');
172
+ }
173
+
174
+ return {
175
+ ...parentPropPanel.schema(propPanelProps),
176
+ '-------': { type: 'void', widget: 'Divider' },
177
+
178
+ optionsContainer: {
179
+ title: (propPanelProps as PropPanelWidgetProps).i18n('schemas.select.options'),
180
+ type: 'string',
181
+ widget: 'Card',
182
+ span: 24,
183
+ properties: { options: { widget: 'addOptions', span: 24 } },
184
+ },
185
+ };
186
+ },
187
+ defaultSchema: {
188
+ ...text.propPanel.defaultSchema,
189
+ type: 'select',
190
+ content: 'option1',
191
+ options: ['option1', 'option2'],
192
+ },
193
+ },
194
+ icon: selectIcon,
195
+ };
196
+
197
+ export default schema;
@@ -35,14 +35,17 @@ interface GroupButtonString {
35
35
  key: Formatter;
36
36
  icon: string;
37
37
  type: 'select';
38
- value: String;
38
+ value: string;
39
39
  }
40
40
 
41
41
  export type GroupButton = GroupButtonBoolean | GroupButtonString;
42
42
 
43
- export function getExtraFormatterSchema(
44
- i18n: (key: keyof Dict | string) => string
45
- ): Record<string, any> {
43
+ export function getExtraFormatterSchema(i18n: (key: keyof Dict | string) => string): {
44
+ title: string;
45
+ widget: string;
46
+ buttons: GroupButton[];
47
+ span: number;
48
+ } {
46
49
  const buttons: GroupButton[] = [
47
50
  { key: Formatter.STRIKETHROUGH, icon: TextStrikethroughIcon, type: 'boolean' },
48
51
  { key: Formatter.UNDERLINE, icon: TextUnderlineIcon, type: 'boolean' },
@@ -228,7 +228,7 @@ export const buildStyledTextContainer = async (arg: UIRenderProps<TextSchema>, v
228
228
  };
229
229
 
230
230
  const textBlock = document.createElement('div');
231
- textBlock.id = 'text-' + schema.id;
231
+ textBlock.id = 'text-' + String(schema.id);
232
232
  Object.assign(textBlock.style, textBlockStyle);
233
233
 
234
234
  container.appendChild(textBlock);
@@ -265,7 +265,7 @@ export const makeElementPlainTextContentEditable = (element: HTMLElement) => {
265
265
  });
266
266
  };
267
267
 
268
- const mapVerticalAlignToFlex = (verticalAlignmentValue: string | undefined) => {
268
+ export const mapVerticalAlignToFlex = (verticalAlignmentValue: string | undefined) => {
269
269
  switch (verticalAlignmentValue) {
270
270
  case VERTICAL_ALIGN_TOP:
271
271
  return 'flex-start';
@@ -277,7 +277,7 @@ const mapVerticalAlignToFlex = (verticalAlignmentValue: string | undefined) => {
277
277
  return 'flex-start';
278
278
  };
279
279
 
280
- const getBackgroundColor = (value: string, schema: TextSchema) => {
280
+ export const getBackgroundColor = (value: string, schema: { backgroundColor?: string }) => {
281
281
  if (!value || !schema.backgroundColor) return 'transparent';
282
- return schema.backgroundColor as string;
282
+ return schema.backgroundColor;
283
283
  };