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