labellife-design-tool 2.2.7 → 2.2.9

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/index.js CHANGED
@@ -30,6 +30,9 @@ var CloseIcon = require('@mui/icons-material/Close');
30
30
  var InputIcon = require('@mui/icons-material/Input');
31
31
  var CalendarTodayIcon = require('@mui/icons-material/CalendarToday');
32
32
  var NumbersIcon = require('@mui/icons-material/Numbers');
33
+ var RadioButtonCheckedIcon = require('@mui/icons-material/RadioButtonChecked');
34
+ var FormatListBulletedIcon = require('@mui/icons-material/FormatListBulleted');
35
+ var AddIcon = require('@mui/icons-material/Add');
33
36
  var ArrowDropDownIcon = require('@mui/icons-material/ArrowDropDown');
34
37
  var FileUploadIcon = require('@mui/icons-material/FileUpload');
35
38
  var UndoIcon = require('@mui/icons-material/Undo');
@@ -6899,7 +6902,7 @@ function ImagesGrid(_ref) {
6899
6902
  });
6900
6903
  }
6901
6904
 
6902
- var _excluded$2 = ["inputField", "promptText", "inputType", "required", "placeholder"];
6905
+ var _excluded$2 = ["inputField", "promptText", "inputType", "required", "placeholder", "options", "minSelections", "maxSelections"];
6903
6906
  var IMAGE_PLACEHOLDER_SRC = "data:image/svg+xml;charset=utf-8,".concat(encodeURIComponent("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"400\" height=\"400\" viewBox=\"0 0 400 400\">\n <rect width=\"400\" height=\"400\" fill=\"#f0f2f5\" rx=\"12\"/>\n <rect x=\"110\" y=\"90\" width=\"180\" height=\"145\" rx=\"10\" fill=\"#dde1e7\"/>\n <circle cx=\"158\" cy=\"135\" r=\"22\" fill=\"#f0f2f5\"/>\n <polygon points=\"110,235 168,163 210,205 250,163 290,235\" fill=\"#c8cdd6\"/>\n <rect x=\"140\" y=\"268\" width=\"120\" height=\"14\" rx=\"7\" fill=\"#c8cdd6\"/>\n <rect x=\"160\" y=\"292\" width=\"80\" height=\"10\" rx=\"5\" fill=\"#dde1e7\"/>\n </svg>"));
6904
6907
 
6905
6908
  // ── Date formatting helpers ──────────────────────────────────────────
@@ -6941,12 +6944,84 @@ function formatDate$1(date, format) {
6941
6944
  }
6942
6945
  }
6943
6946
 
6947
+ // ── Options list editor ──────────────────────────────────────────────
6948
+ var OptionsEditor = function OptionsEditor(_ref) {
6949
+ var options = _ref.options,
6950
+ _onChange = _ref.onChange;
6951
+ return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
6952
+ sx: {
6953
+ ml: 6.5,
6954
+ mr: 1,
6955
+ display: 'flex',
6956
+ flexDirection: 'column',
6957
+ gap: 0.75
6958
+ },
6959
+ children: [options.map(function (opt, i) {
6960
+ return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
6961
+ sx: {
6962
+ display: 'flex',
6963
+ gap: 0.5,
6964
+ alignItems: 'center'
6965
+ },
6966
+ children: [/*#__PURE__*/jsxRuntime.jsx(material.TextField, {
6967
+ size: "small",
6968
+ value: opt,
6969
+ onChange: function onChange(e) {
6970
+ var next = _toConsumableArray(options);
6971
+ next[i] = e.target.value;
6972
+ _onChange(next);
6973
+ },
6974
+ placeholder: "Option ".concat(i + 1),
6975
+ sx: {
6976
+ flex: 1,
6977
+ '& .MuiInputBase-input': {
6978
+ fontSize: 12,
6979
+ py: 0.75
6980
+ }
6981
+ }
6982
+ }), /*#__PURE__*/jsxRuntime.jsx(material.IconButton, {
6983
+ size: "small",
6984
+ onClick: function onClick() {
6985
+ return _onChange(options.filter(function (_, j) {
6986
+ return j !== i;
6987
+ }));
6988
+ },
6989
+ disabled: options.length <= 1,
6990
+ sx: {
6991
+ color: '#bbb',
6992
+ '&:hover': {
6993
+ color: '#e57373'
6994
+ }
6995
+ },
6996
+ children: /*#__PURE__*/jsxRuntime.jsx(DeleteIcon, {
6997
+ fontSize: "small"
6998
+ })
6999
+ })]
7000
+ }, i);
7001
+ }), /*#__PURE__*/jsxRuntime.jsx(material.Button, {
7002
+ size: "small",
7003
+ startIcon: /*#__PURE__*/jsxRuntime.jsx(AddIcon, {}),
7004
+ onClick: function onClick() {
7005
+ return _onChange([].concat(_toConsumableArray(options), ['']));
7006
+ },
7007
+ sx: {
7008
+ alignSelf: 'flex-start',
7009
+ fontSize: 11,
7010
+ textTransform: 'none',
7011
+ color: '#0d83cd',
7012
+ p: 0.5
7013
+ },
7014
+ children: "Add option"
7015
+ })]
7016
+ });
7017
+ };
7018
+
6944
7019
  // ── Card component ───────────────────────────────────────────────────
6945
- var InputFieldCard = function InputFieldCard(_ref) {
6946
- var icon = _ref.icon,
6947
- label = _ref.label,
6948
- description = _ref.description,
6949
- onClick = _ref.onClick;
7020
+ var InputFieldCard = function InputFieldCard(_ref2) {
7021
+ var icon = _ref2.icon,
7022
+ label = _ref2.label,
7023
+ description = _ref2.description,
7024
+ onClick = _ref2.onClick;
6950
7025
  return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
6951
7026
  onClick: onClick,
6952
7027
  sx: {
@@ -7002,8 +7077,8 @@ var InputFieldCard = function InputFieldCard(_ref) {
7002
7077
  };
7003
7078
 
7004
7079
  // ── Panel content ────────────────────────────────────────────────────
7005
- var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7006
- var store = _ref2.store;
7080
+ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref3) {
7081
+ var store = _ref3.store;
7007
7082
  var _useState = React.useState('MM-DD-YYYY'),
7008
7083
  _useState2 = _slicedToArray(_useState, 2),
7009
7084
  dateFormat = _useState2[0],
@@ -7040,6 +7115,34 @@ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7040
7115
  _useState16 = _slicedToArray(_useState15, 2),
7041
7116
  imageRequired = _useState16[0],
7042
7117
  setImageRequired = _useState16[1];
7118
+ var _useState17 = React.useState(''),
7119
+ _useState18 = _slicedToArray(_useState17, 2),
7120
+ radioPrompt = _useState18[0],
7121
+ setRadioPrompt = _useState18[1];
7122
+ var _useState19 = React.useState(false),
7123
+ _useState20 = _slicedToArray(_useState19, 2),
7124
+ radioRequired = _useState20[0],
7125
+ setRadioRequired = _useState20[1];
7126
+ var _useState21 = React.useState(['Option 1', 'Option 2']),
7127
+ _useState22 = _slicedToArray(_useState21, 2),
7128
+ radioOptions = _useState22[0],
7129
+ setRadioOptions = _useState22[1];
7130
+ var _useState23 = React.useState(''),
7131
+ _useState24 = _slicedToArray(_useState23, 2),
7132
+ listPrompt = _useState24[0],
7133
+ setListPrompt = _useState24[1];
7134
+ var _useState25 = React.useState(0),
7135
+ _useState26 = _slicedToArray(_useState25, 2),
7136
+ listMinSelections = _useState26[0],
7137
+ setListMinSelections = _useState26[1];
7138
+ var _useState27 = React.useState(2),
7139
+ _useState28 = _slicedToArray(_useState27, 2),
7140
+ listMaxSelections = _useState28[0],
7141
+ setListMaxSelections = _useState28[1];
7142
+ var _useState29 = React.useState(['Option 1', 'Option 2']),
7143
+ _useState30 = _slicedToArray(_useState29, 2),
7144
+ listOptions = _useState30[0],
7145
+ setListOptions = _useState30[1];
7043
7146
  var addInputElement = function addInputElement(inputType) {
7044
7147
  var extra = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7045
7148
  var page = store.activePage;
@@ -7082,6 +7185,16 @@ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7082
7185
  placeholder = t('sidePanel.inputFields.integerPlaceholder', 'Enter number');
7083
7186
  defaultPrompt = t('sidePanel.inputFields.defaultIntegerPrompt', 'Please enter a number');
7084
7187
  break;
7188
+ case 'radio':
7189
+ dummyText = (extra.options || []).filter(Boolean)[0] || 'Option 1';
7190
+ placeholder = t('sidePanel.inputFields.radioPlaceholder', 'Select an option');
7191
+ defaultPrompt = t('sidePanel.inputFields.defaultRadioPrompt', 'Please select an option');
7192
+ break;
7193
+ case 'list':
7194
+ dummyText = (extra.options || []).filter(Boolean).slice(0, 2).join(', ') || 'Option 1, Option 2';
7195
+ placeholder = t('sidePanel.inputFields.listPlaceholder', 'Select options');
7196
+ defaultPrompt = t('sidePanel.inputFields.defaultListPrompt', 'Please select options');
7197
+ break;
7085
7198
  default:
7086
7199
  dummyText = 'Input';
7087
7200
  placeholder = 'Input';
@@ -7100,7 +7213,7 @@ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7100
7213
  fontFamily: 'Roboto',
7101
7214
  align: 'center',
7102
7215
  fill: '#333333',
7103
- custom: _objectSpread2({
7216
+ custom: _objectSpread2(_objectSpread2(_objectSpread2({
7104
7217
  inputField: true,
7105
7218
  inputType: inputType,
7106
7219
  placeholder: placeholder,
@@ -7108,6 +7221,11 @@ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7108
7221
  required: extra.required || false
7109
7222
  }, inputType === 'date' ? {
7110
7223
  dateFormat: extra.dateFormat || 'MM-DD-YYYY'
7224
+ } : {}), ['radio', 'list'].includes(inputType) ? {
7225
+ options: (extra.options || []).filter(Boolean)
7226
+ } : {}), inputType === 'list' ? {
7227
+ minSelections: extra.minSelections || 0,
7228
+ maxSelections: extra.maxSelections || 0
7111
7229
  } : {})
7112
7230
  });
7113
7231
  }
@@ -7349,6 +7467,138 @@ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7349
7467
  sx: {
7350
7468
  ml: 5.5
7351
7469
  }
7470
+ }), /*#__PURE__*/jsxRuntime.jsx(InputFieldCard, {
7471
+ icon: /*#__PURE__*/jsxRuntime.jsx(RadioButtonCheckedIcon, {
7472
+ fontSize: "small"
7473
+ }),
7474
+ label: t('sidePanel.inputFields.radioInput', 'Radio Input'),
7475
+ description: t('sidePanel.inputFields.radioInputDesc', 'Single option selection'),
7476
+ onClick: function onClick() {
7477
+ return addInputElement('radio', {
7478
+ promptText: radioPrompt,
7479
+ required: radioRequired,
7480
+ options: radioOptions
7481
+ });
7482
+ }
7483
+ }), /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
7484
+ size: "small",
7485
+ placeholder: t('sidePanel.inputFields.promptTextHint', 'Prompt text shown to user...'),
7486
+ value: radioPrompt,
7487
+ onChange: function onChange(e) {
7488
+ return setRadioPrompt(e.target.value);
7489
+ },
7490
+ sx: {
7491
+ ml: 6.5,
7492
+ mr: 1,
7493
+ '& .MuiInputBase-input': {
7494
+ fontSize: 12,
7495
+ py: 0.75
7496
+ }
7497
+ }
7498
+ }), /*#__PURE__*/jsxRuntime.jsx(material.FormControlLabel, {
7499
+ control: /*#__PURE__*/jsxRuntime.jsx(material.Checkbox, {
7500
+ size: "small",
7501
+ checked: radioRequired,
7502
+ onChange: function onChange(e) {
7503
+ return setRadioRequired(e.target.checked);
7504
+ }
7505
+ }),
7506
+ label: /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
7507
+ sx: {
7508
+ fontSize: 12
7509
+ },
7510
+ children: t('sidePanel.inputFields.required', 'Required')
7511
+ }),
7512
+ sx: {
7513
+ ml: 5.5
7514
+ }
7515
+ }), /*#__PURE__*/jsxRuntime.jsx(OptionsEditor, {
7516
+ options: radioOptions,
7517
+ onChange: setRadioOptions
7518
+ }), /*#__PURE__*/jsxRuntime.jsx(InputFieldCard, {
7519
+ icon: /*#__PURE__*/jsxRuntime.jsx(FormatListBulletedIcon, {
7520
+ fontSize: "small"
7521
+ }),
7522
+ label: t('sidePanel.inputFields.listInput', 'List Input'),
7523
+ description: t('sidePanel.inputFields.listInputDesc', 'Multiple option selection'),
7524
+ onClick: function onClick() {
7525
+ return addInputElement('list', {
7526
+ promptText: listPrompt,
7527
+ minSelections: listMinSelections,
7528
+ maxSelections: listMaxSelections,
7529
+ options: listOptions
7530
+ });
7531
+ }
7532
+ }), /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
7533
+ size: "small",
7534
+ placeholder: t('sidePanel.inputFields.promptTextHint', 'Prompt text shown to user...'),
7535
+ value: listPrompt,
7536
+ onChange: function onChange(e) {
7537
+ return setListPrompt(e.target.value);
7538
+ },
7539
+ sx: {
7540
+ ml: 6.5,
7541
+ mr: 1,
7542
+ '& .MuiInputBase-input': {
7543
+ fontSize: 12,
7544
+ py: 0.75
7545
+ }
7546
+ }
7547
+ }), /*#__PURE__*/jsxRuntime.jsx(OptionsEditor, {
7548
+ options: listOptions,
7549
+ onChange: setListOptions
7550
+ }), /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
7551
+ sx: {
7552
+ display: 'flex',
7553
+ gap: 1,
7554
+ ml: 6.5,
7555
+ mr: 1
7556
+ },
7557
+ children: [/*#__PURE__*/jsxRuntime.jsx(material.TextField, {
7558
+ size: "small",
7559
+ type: "number",
7560
+ label: t('sidePanel.inputFields.minSelections', 'Min select'),
7561
+ value: listMinSelections,
7562
+ onChange: function onChange(e) {
7563
+ return setListMinSelections(Math.max(0, parseInt(e.target.value) || 0));
7564
+ },
7565
+ inputProps: {
7566
+ min: 0
7567
+ },
7568
+ sx: {
7569
+ flex: 1,
7570
+ '& .MuiInputBase-input': {
7571
+ fontSize: 12,
7572
+ py: 0.75
7573
+ }
7574
+ }
7575
+ }), /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
7576
+ size: "small",
7577
+ type: "number",
7578
+ label: t('sidePanel.inputFields.maxSelections', 'Max select'),
7579
+ value: listMaxSelections,
7580
+ onChange: function onChange(e) {
7581
+ return setListMaxSelections(Math.max(0, parseInt(e.target.value) || 0));
7582
+ },
7583
+ inputProps: {
7584
+ min: 0
7585
+ },
7586
+ sx: {
7587
+ flex: 1,
7588
+ '& .MuiInputBase-input': {
7589
+ fontSize: 12,
7590
+ py: 0.75
7591
+ }
7592
+ }
7593
+ })]
7594
+ }), /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
7595
+ variant: "caption",
7596
+ sx: {
7597
+ ml: 6.5,
7598
+ color: '#999',
7599
+ fontSize: 10
7600
+ },
7601
+ children: listMinSelections > 0 ? "Required \xB7 min ".concat(listMinSelections).concat(listMaxSelections > 0 ? ", max ".concat(listMaxSelections) : ', no max') : "Optional \xB7 max ".concat(listMaxSelections > 0 ? listMaxSelections : '∞')
7352
7602
  })]
7353
7603
  }), /*#__PURE__*/jsxRuntime.jsx(material.Divider, {
7354
7604
  sx: {
@@ -7378,21 +7628,33 @@ var InputFieldsPanelContent = mobxReactLite.observer(function (_ref2) {
7378
7628
  });
7379
7629
 
7380
7630
  // ── Mark-as-variable sub-form ─────────────────────────────────────────
7381
- var MarkAsVariableForm = mobxReactLite.observer(function (_ref3) {
7631
+ var MarkAsVariableForm = mobxReactLite.observer(function (_ref4) {
7382
7632
  var _selectedElement$cust;
7383
- var store = _ref3.store;
7384
- var _useState17 = React.useState(''),
7385
- _useState18 = _slicedToArray(_useState17, 2),
7386
- markLabel = _useState18[0],
7387
- setMarkLabel = _useState18[1];
7388
- var _useState19 = React.useState(false),
7389
- _useState20 = _slicedToArray(_useState19, 2),
7390
- markRequired = _useState20[0],
7391
- setMarkRequired = _useState20[1];
7392
- var _useState21 = React.useState('text'),
7393
- _useState22 = _slicedToArray(_useState21, 2),
7394
- markInputType = _useState22[0],
7395
- setMarkInputType = _useState22[1];
7633
+ var store = _ref4.store;
7634
+ var _useState31 = React.useState(''),
7635
+ _useState32 = _slicedToArray(_useState31, 2),
7636
+ markLabel = _useState32[0],
7637
+ setMarkLabel = _useState32[1];
7638
+ var _useState33 = React.useState(false),
7639
+ _useState34 = _slicedToArray(_useState33, 2),
7640
+ markRequired = _useState34[0],
7641
+ setMarkRequired = _useState34[1];
7642
+ var _useState35 = React.useState('text'),
7643
+ _useState36 = _slicedToArray(_useState35, 2),
7644
+ markInputType = _useState36[0],
7645
+ setMarkInputType = _useState36[1];
7646
+ var _useState37 = React.useState(['Option 1', 'Option 2']),
7647
+ _useState38 = _slicedToArray(_useState37, 2),
7648
+ markOptions = _useState38[0],
7649
+ setMarkOptions = _useState38[1];
7650
+ var _useState39 = React.useState(0),
7651
+ _useState40 = _slicedToArray(_useState39, 2),
7652
+ markMinSelections = _useState40[0],
7653
+ setMarkMinSelections = _useState40[1];
7654
+ var _useState41 = React.useState(2),
7655
+ _useState42 = _slicedToArray(_useState41, 2),
7656
+ markMaxSelections = _useState42[0],
7657
+ setMarkMaxSelections = _useState42[1];
7396
7658
  var selectedIds = store.selectedElementsIds || [];
7397
7659
  var selectedElement = selectedIds.length === 1 ? store.getElementById(selectedIds[0]) : null;
7398
7660
  var isImageElement = (selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.type) === 'image';
@@ -7401,37 +7663,52 @@ var MarkAsVariableForm = mobxReactLite.observer(function (_ref3) {
7401
7663
  var isAlreadyVariable = !!(selectedElement !== null && selectedElement !== void 0 && (_selectedElement$cust = selectedElement.custom) !== null && _selectedElement$cust !== void 0 && _selectedElement$cust.inputField);
7402
7664
  React.useEffect(function () {
7403
7665
  if (selectedElement && isSupportedElement) {
7404
- var _selectedElement$cust2, _selectedElement$cust3, _selectedElement$cust4;
7666
+ var _selectedElement$cust2, _selectedElement$cust3, _selectedElement$cust4, _selectedElement$cust5, _selectedElement$cust6, _selectedElement$cust7;
7405
7667
  setMarkLabel(((_selectedElement$cust2 = selectedElement.custom) === null || _selectedElement$cust2 === void 0 ? void 0 : _selectedElement$cust2.promptText) || '');
7406
7668
  setMarkRequired(!!((_selectedElement$cust3 = selectedElement.custom) !== null && _selectedElement$cust3 !== void 0 && _selectedElement$cust3.required));
7407
7669
  setMarkInputType(isImageElement ? 'image' : ((_selectedElement$cust4 = selectedElement.custom) === null || _selectedElement$cust4 === void 0 ? void 0 : _selectedElement$cust4.inputType) || 'text');
7670
+ setMarkOptions(((_selectedElement$cust5 = selectedElement.custom) === null || _selectedElement$cust5 === void 0 ? void 0 : _selectedElement$cust5.options) || ['Option 1', 'Option 2']);
7671
+ setMarkMinSelections(((_selectedElement$cust6 = selectedElement.custom) === null || _selectedElement$cust6 === void 0 ? void 0 : _selectedElement$cust6.minSelections) || 0);
7672
+ setMarkMaxSelections(((_selectedElement$cust7 = selectedElement.custom) === null || _selectedElement$cust7 === void 0 ? void 0 : _selectedElement$cust7.maxSelections) || 2);
7408
7673
  } else {
7409
7674
  setMarkLabel('');
7410
7675
  setMarkRequired(false);
7411
7676
  setMarkInputType('text');
7677
+ setMarkOptions(['Option 1', 'Option 2']);
7678
+ setMarkMinSelections(0);
7679
+ setMarkMaxSelections(2);
7412
7680
  }
7413
7681
  }, [selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.id]);
7414
7682
  var handleMark = function handleMark() {
7415
7683
  if (!selectedElement || !markLabel.trim()) return;
7684
+ var effectiveType = isImageElement ? 'image' : markInputType;
7416
7685
  selectedElement.set({
7417
- custom: _objectSpread2(_objectSpread2({}, selectedElement.custom), {}, {
7686
+ custom: _objectSpread2(_objectSpread2(_objectSpread2({}, selectedElement.custom), {}, {
7418
7687
  inputField: true,
7419
7688
  promptText: markLabel.trim(),
7420
- inputType: isImageElement ? 'image' : markInputType,
7689
+ inputType: effectiveType,
7421
7690
  required: markRequired
7422
- })
7691
+ }, ['radio', 'list'].includes(effectiveType) ? {
7692
+ options: markOptions.filter(Boolean)
7693
+ } : {}), effectiveType === 'list' ? {
7694
+ minSelections: markMinSelections,
7695
+ maxSelections: markMaxSelections
7696
+ } : {})
7423
7697
  });
7424
7698
  store.history.addUndoState();
7425
7699
  };
7426
7700
  var handleUnmark = function handleUnmark() {
7427
7701
  if (!selectedElement) return;
7428
- var _ref4 = selectedElement.custom || {};
7429
- _ref4.inputField;
7430
- _ref4.promptText;
7431
- _ref4.inputType;
7432
- _ref4.required;
7433
- _ref4.placeholder;
7434
- var rest = _objectWithoutProperties(_ref4, _excluded$2);
7702
+ var _ref5 = selectedElement.custom || {};
7703
+ _ref5.inputField;
7704
+ _ref5.promptText;
7705
+ _ref5.inputType;
7706
+ _ref5.required;
7707
+ _ref5.placeholder;
7708
+ _ref5.options;
7709
+ _ref5.minSelections;
7710
+ _ref5.maxSelections;
7711
+ var rest = _objectWithoutProperties(_ref5, _excluded$2);
7435
7712
  selectedElement.set({
7436
7713
  custom: rest
7437
7714
  });
@@ -7556,9 +7833,84 @@ var MarkAsVariableForm = mobxReactLite.observer(function (_ref3) {
7556
7833
  fontSize: 12
7557
7834
  },
7558
7835
  children: t('sidePanel.inputFields.dateInput', 'Date Input')
7836
+ }), /*#__PURE__*/jsxRuntime.jsx(material.MenuItem, {
7837
+ value: "radio",
7838
+ sx: {
7839
+ fontSize: 12
7840
+ },
7841
+ children: t('sidePanel.inputFields.radioInput', 'Radio Input')
7842
+ }), /*#__PURE__*/jsxRuntime.jsx(material.MenuItem, {
7843
+ value: "list",
7844
+ sx: {
7845
+ fontSize: 12
7846
+ },
7847
+ children: t('sidePanel.inputFields.listInput', 'List Input')
7559
7848
  })]
7560
7849
  })]
7561
- }), /*#__PURE__*/jsxRuntime.jsx(material.FormControlLabel, {
7850
+ }), isTextElement && (markInputType === 'radio' || markInputType === 'list') && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
7851
+ children: [/*#__PURE__*/jsxRuntime.jsx(material.Typography, {
7852
+ variant: "caption",
7853
+ sx: {
7854
+ color: '#888',
7855
+ fontSize: 11
7856
+ },
7857
+ children: "Options"
7858
+ }), /*#__PURE__*/jsxRuntime.jsx(OptionsEditor, {
7859
+ options: markOptions,
7860
+ onChange: setMarkOptions
7861
+ })]
7862
+ }), isTextElement && markInputType === 'list' && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
7863
+ children: [/*#__PURE__*/jsxRuntime.jsxs(material.Box, {
7864
+ sx: {
7865
+ display: 'flex',
7866
+ gap: 1
7867
+ },
7868
+ children: [/*#__PURE__*/jsxRuntime.jsx(material.TextField, {
7869
+ size: "small",
7870
+ type: "number",
7871
+ label: t('sidePanel.inputFields.minSelections', 'Min select'),
7872
+ value: markMinSelections,
7873
+ onChange: function onChange(e) {
7874
+ return setMarkMinSelections(Math.max(0, parseInt(e.target.value) || 0));
7875
+ },
7876
+ inputProps: {
7877
+ min: 0
7878
+ },
7879
+ sx: {
7880
+ flex: 1,
7881
+ '& .MuiInputBase-input': {
7882
+ fontSize: 12,
7883
+ py: 0.75
7884
+ }
7885
+ }
7886
+ }), /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
7887
+ size: "small",
7888
+ type: "number",
7889
+ label: t('sidePanel.inputFields.maxSelections', 'Max select'),
7890
+ value: markMaxSelections,
7891
+ onChange: function onChange(e) {
7892
+ return setMarkMaxSelections(Math.max(0, parseInt(e.target.value) || 0));
7893
+ },
7894
+ inputProps: {
7895
+ min: 0
7896
+ },
7897
+ sx: {
7898
+ flex: 1,
7899
+ '& .MuiInputBase-input': {
7900
+ fontSize: 12,
7901
+ py: 0.75
7902
+ }
7903
+ }
7904
+ })]
7905
+ }), /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
7906
+ variant: "caption",
7907
+ sx: {
7908
+ color: '#999',
7909
+ fontSize: 10
7910
+ },
7911
+ children: markMinSelections > 0 ? "Required \xB7 min ".concat(markMinSelections).concat(markMaxSelections > 0 ? ", max ".concat(markMaxSelections) : ', no max') : "Optional \xB7 max ".concat(markMaxSelections > 0 ? markMaxSelections : '∞')
7912
+ })]
7913
+ }), (!isTextElement || markInputType !== 'list') && /*#__PURE__*/jsxRuntime.jsx(material.FormControlLabel, {
7562
7914
  control: /*#__PURE__*/jsxRuntime.jsx(material.Checkbox, {
7563
7915
  size: "small",
7564
7916
  checked: markRequired,
@@ -9599,8 +9951,10 @@ var TextElementComponent = mobxReactLite.observer(function (_ref) {
9599
9951
  var scaleY = absScale.y;
9600
9952
  var cssFontStyle = element.fontStyle === 'italic' ? 'italic' : 'normal';
9601
9953
  var cssFontWeight = String(element.fontWeight || 'normal');
9954
+ var originalText = element.text;
9602
9955
  var textarea = document.createElement('textarea');
9603
- textarea.value = element.text;
9956
+ textarea.value = '';
9957
+ textarea.placeholder = originalText;
9604
9958
  textarea.style.position = 'absolute';
9605
9959
  textarea.style.top = "".concat(textPosition.y, "px");
9606
9960
  textarea.style.left = "".concat(textPosition.x, "px");
@@ -9633,15 +9987,21 @@ var TextElementComponent = mobxReactLite.observer(function (_ref) {
9633
9987
  textarea.style.wordBreak = 'break-word';
9634
9988
  textarea.style.minHeight = '0';
9635
9989
  textarea.style.minWidth = '0';
9990
+
9991
+ // Placeholder inherits the element's text color at 40% opacity
9992
+ var placeholderStyle = document.createElement('style');
9993
+ placeholderStyle.textContent = "\n textarea:placeholder-shown { opacity: 1; }\n textarea::placeholder { color: ".concat(element.fill, "; opacity: 0.4; }\n ");
9994
+ stageContainer.appendChild(placeholderStyle);
9636
9995
  stageContainer.appendChild(textarea);
9637
9996
  textarea.focus();
9638
- textarea.select();
9639
9997
  var removed = false;
9640
9998
  var removeTextarea = function removeTextarea() {
9999
+ var cancel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
9641
10000
  if (removed) return;
9642
10001
  removed = true;
10002
+ var newText = !cancel && textarea.value.length > 0 ? textarea.value : originalText;
9643
10003
  element.set({
9644
- text: textarea.value
10004
+ text: newText
9645
10005
  });
9646
10006
  element.toggleEditMode(false);
9647
10007
  if (grp) grp.show();
@@ -9649,12 +10009,15 @@ var TextElementComponent = mobxReactLite.observer(function (_ref) {
9649
10009
  if (textarea.parentNode) {
9650
10010
  textarea.parentNode.removeChild(textarea);
9651
10011
  }
10012
+ if (placeholderStyle.parentNode) {
10013
+ placeholderStyle.parentNode.removeChild(placeholderStyle);
10014
+ }
9652
10015
  };
9653
- textarea.addEventListener('blur', removeTextarea);
10016
+ textarea.addEventListener('blur', function () {
10017
+ return removeTextarea(false);
10018
+ });
9654
10019
  textarea.addEventListener('keydown', function (e) {
9655
- if (e.key === 'Escape') {
9656
- removeTextarea();
9657
- }
10020
+ if (e.key === 'Escape') removeTextarea(true);
9658
10021
  });
9659
10022
  };
9660
10023
 
@@ -10312,12 +10675,20 @@ var SingleFieldDialog = function SingleFieldDialog(_ref) {
10312
10675
  imagePreview = _useState4[0],
10313
10676
  setImagePreview = _useState4[1];
10314
10677
  var fileInputRef = React.useRef(null);
10678
+ var _useState5 = React.useState([]),
10679
+ _useState6 = _slicedToArray(_useState5, 2),
10680
+ selectedItems = _useState6[0],
10681
+ setSelectedItems = _useState6[1];
10315
10682
  var config = getInputFieldsConfig();
10316
10683
  var custom = field.custom || {};
10317
10684
  var inputType = custom.inputType || 'text';
10318
10685
  var promptText = custom.promptText || custom.placeholder || 'Please provide input';
10319
10686
  var dateFormat = custom.dateFormat || 'MM-DD-YYYY';
10320
10687
  var isRequired = custom.required === true;
10688
+ var options = custom.options || [];
10689
+ var minSelections = custom.minSelections || 0;
10690
+ var maxSelections = custom.maxSelections || options.length;
10691
+ var isSubmitDisabled = inputType === 'list' ? selectedItems.length < minSelections : isRequired && !value;
10321
10692
  var logoUrl = config.logoUrl || null;
10322
10693
  var headerText = config.headerText || null;
10323
10694
  var accentColor = config.accentColor || '#0d83cd';
@@ -10325,6 +10696,7 @@ var SingleFieldDialog = function SingleFieldDialog(_ref) {
10325
10696
  React.useEffect(function () {
10326
10697
  setValue('');
10327
10698
  setImagePreview(null);
10699
+ setSelectedItems([]);
10328
10700
  }, [field.id]);
10329
10701
  var handleImageSelect = function handleImageSelect(e) {
10330
10702
  var _e$target$files;
@@ -10344,12 +10716,14 @@ var SingleFieldDialog = function SingleFieldDialog(_ref) {
10344
10716
  var dateObj = parseDateFromFormat(value);
10345
10717
  var formatted = formatDate(dateObj, dateFormat);
10346
10718
  onSubmit(field.id, formatted);
10719
+ } else if (inputType === 'list') {
10720
+ onSubmit(field.id, selectedItems.join(', '));
10347
10721
  } else {
10348
10722
  onSubmit(field.id, value);
10349
10723
  }
10350
10724
  };
10351
10725
  var handleKeyDown = function handleKeyDown(e) {
10352
- if (e.key === 'Enter' && inputType !== 'image') handleSubmit();
10726
+ if (e.key === 'Enter' && inputType !== 'image' && inputType !== 'list' && inputType !== 'radio') handleSubmit();
10353
10727
  };
10354
10728
  var renderInput = function renderInput() {
10355
10729
  var sharedSx = _objectSpread2({
@@ -10489,6 +10863,119 @@ var SingleFieldDialog = function SingleFieldDialog(_ref) {
10489
10863
  })]
10490
10864
  })]
10491
10865
  });
10866
+ case 'radio':
10867
+ return /*#__PURE__*/jsxRuntime.jsx(material.RadioGroup, {
10868
+ value: value,
10869
+ onChange: function onChange(e) {
10870
+ return setValue(e.target.value);
10871
+ },
10872
+ sx: {
10873
+ mt: 1,
10874
+ gap: 1
10875
+ },
10876
+ children: options.map(function (opt) {
10877
+ return /*#__PURE__*/jsxRuntime.jsx(material.FormControlLabel, {
10878
+ value: opt,
10879
+ control: /*#__PURE__*/jsxRuntime.jsx(material.Radio, {
10880
+ sx: {
10881
+ color: '#d0d5dd',
10882
+ '&.Mui-checked': {
10883
+ color: accentColor
10884
+ }
10885
+ }
10886
+ }),
10887
+ label: /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
10888
+ sx: {
10889
+ fontSize: 18
10890
+ },
10891
+ children: opt
10892
+ }),
10893
+ sx: {
10894
+ m: 0,
10895
+ border: '1px solid',
10896
+ borderColor: value === opt ? accentColor : '#d0d5dd',
10897
+ borderRadius: '8px',
10898
+ px: 2,
10899
+ py: 0.75,
10900
+ transition: 'all 0.15s ease',
10901
+ backgroundColor: value === opt ? 'rgba(13,131,205,0.04)' : 'transparent',
10902
+ '&:hover': {
10903
+ borderColor: accentColor,
10904
+ backgroundColor: 'rgba(13,131,205,0.03)'
10905
+ }
10906
+ }
10907
+ }, opt);
10908
+ })
10909
+ });
10910
+ case 'list':
10911
+ {
10912
+ var isAtMax = maxSelections > 0 && selectedItems.length >= maxSelections;
10913
+ return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
10914
+ sx: {
10915
+ mt: 1
10916
+ },
10917
+ children: [/*#__PURE__*/jsxRuntime.jsx(material.FormGroup, {
10918
+ sx: {
10919
+ gap: 1
10920
+ },
10921
+ children: options.map(function (opt) {
10922
+ var checked = selectedItems.includes(opt);
10923
+ var disabled = !checked && isAtMax;
10924
+ return /*#__PURE__*/jsxRuntime.jsx(material.FormControlLabel, {
10925
+ control: /*#__PURE__*/jsxRuntime.jsx(material.Checkbox, {
10926
+ checked: checked,
10927
+ disabled: disabled,
10928
+ onChange: function onChange(e) {
10929
+ if (e.target.checked) {
10930
+ setSelectedItems(function (prev) {
10931
+ return [].concat(_toConsumableArray(prev), [opt]);
10932
+ });
10933
+ } else {
10934
+ setSelectedItems(function (prev) {
10935
+ return prev.filter(function (i) {
10936
+ return i !== opt;
10937
+ });
10938
+ });
10939
+ }
10940
+ },
10941
+ sx: {
10942
+ color: '#d0d5dd',
10943
+ '&.Mui-checked': {
10944
+ color: accentColor
10945
+ }
10946
+ }
10947
+ }),
10948
+ label: /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
10949
+ sx: {
10950
+ fontSize: 18,
10951
+ opacity: disabled ? 0.45 : 1
10952
+ },
10953
+ children: opt
10954
+ }),
10955
+ sx: {
10956
+ m: 0,
10957
+ border: '1px solid',
10958
+ borderColor: checked ? accentColor : '#d0d5dd',
10959
+ borderRadius: '8px',
10960
+ px: 2,
10961
+ py: 0.75,
10962
+ opacity: disabled ? 0.6 : 1,
10963
+ transition: 'all 0.15s ease',
10964
+ backgroundColor: checked ? 'rgba(13,131,205,0.04)' : 'transparent'
10965
+ }
10966
+ }, opt);
10967
+ })
10968
+ }), /*#__PURE__*/jsxRuntime.jsxs(material.Typography, {
10969
+ variant: "caption",
10970
+ sx: {
10971
+ color: '#999',
10972
+ display: 'block',
10973
+ mt: 1.5
10974
+ },
10975
+ children: [selectedItems.length, maxSelections > 0 ? "/".concat(maxSelections) : '', " selected", minSelections > 0 && " \xB7 min ".concat(minSelections, " required")]
10976
+ })]
10977
+ });
10978
+ }
10492
10979
  case 'text':
10493
10980
  default:
10494
10981
  return /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
@@ -10631,7 +11118,7 @@ var SingleFieldDialog = function SingleFieldDialog(_ref) {
10631
11118
  }), /*#__PURE__*/jsxRuntime.jsx(material.Button, {
10632
11119
  variant: "contained",
10633
11120
  onClick: handleSubmit,
10634
- disabled: isRequired && !value,
11121
+ disabled: isSubmitDisabled,
10635
11122
  sx: _objectSpread2({
10636
11123
  textTransform: 'none',
10637
11124
  fontWeight: 600,
@@ -10647,7 +11134,7 @@ var SingleFieldDialog = function SingleFieldDialog(_ref) {
10647
11134
  }
10648
11135
  }, config.submitButtonStyle),
10649
11136
  children: config.submitButtonText || t('inputFieldsDialog.submit', 'Continue')
10650
- }), !isRequired && /*#__PURE__*/jsxRuntime.jsx(material.Button, {
11137
+ }), (inputType === 'list' ? minSelections === 0 : !isRequired) && /*#__PURE__*/jsxRuntime.jsx(material.Button, {
10651
11138
  variant: "outlined",
10652
11139
  onClick: function onClick() {
10653
11140
  return onSkip(field.id);
@@ -10684,10 +11171,10 @@ var InputFieldsDialog = mobxReactLite.observer(function (_ref2) {
10684
11171
  backTrigger = _ref2$backTrigger === void 0 ? 0 : _ref2$backTrigger;
10685
11172
  // displayIndex counts how many fields have been answered (for step indicator only).
10686
11173
  // Navigation always uses fields[0] — the first remaining pending field.
10687
- var _useState5 = React.useState(0),
10688
- _useState6 = _slicedToArray(_useState5, 2),
10689
- displayIndex = _useState6[0],
10690
- setDisplayIndex = _useState6[1];
11174
+ var _useState7 = React.useState(0),
11175
+ _useState8 = _slicedToArray(_useState7, 2),
11176
+ displayIndex = _useState8[0],
11177
+ setDisplayIndex = _useState8[1];
10691
11178
  var initialTotalRef = React.useRef(0);
10692
11179
  var completedHistoryRef = React.useRef([]);
10693
11180
  var isGoingBackRef = React.useRef(false);
@@ -10832,7 +11319,9 @@ var InputFieldsDialog = mobxReactLite.observer(function (_ref2) {
10832
11319
  text: config.CustomTextDialog,
10833
11320
  date: config.CustomDateDialog,
10834
11321
  integer: config.CustomIntegerDialog,
10835
- image: config.CustomImageDialog
11322
+ image: config.CustomImageDialog,
11323
+ radio: config.CustomRadioDialog,
11324
+ list: config.CustomListDialog
10836
11325
  };
10837
11326
  var fieldType = currentField.custom && currentField.custom.inputType || 'text';
10838
11327
  var PerTypeDialog = TYPE_DIALOG_MAP[fieldType];