sag_components 2.0.0-beta329 → 2.0.0-beta330

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/index.js CHANGED
@@ -12405,16 +12405,13 @@ const Td$1 = styled__default["default"].td`
12405
12405
  `;
12406
12406
  const Tr = styled__default["default"].tr`
12407
12407
  border-bottom: 1px solid #f3f4f6;
12408
- ${_ref => {
12409
- let {
12410
- enableHover,
12411
- selectHoverColor
12412
- } = _ref;
12413
- return enableHover && `&:hover {
12408
+ ${({
12409
+ enableHover,
12410
+ selectHoverColor
12411
+ }) => enableHover && `&:hover {
12414
12412
  background-color: ${selectHoverColor};
12415
12413
  cursor: pointer;
12416
- }`;
12417
- }}
12414
+ }`}
12418
12415
  `;
12419
12416
  const InfoText = styled__default["default"].div`
12420
12417
  font-weight: 400;
@@ -49065,17 +49062,83 @@ const AddNegotiatedBrand = styled__default["default"].label`
49065
49062
  font-family: Poppins;
49066
49063
  font-size: 15px;
49067
49064
  `;
49068
- const NegotiatedTextarea = styled__default["default"].textarea`
49065
+ const AutocompleteWrapper = styled__default["default"].div`
49066
+ position: relative;
49069
49067
  width: 90%;
49070
- min-height: 220px;
49071
49068
  margin-top: 8px;
49069
+ `;
49070
+ const NegotiatedTextarea = styled__default["default"].textarea`
49071
+ width: 100%;
49072
+ min-height: 220px;
49072
49073
  border: 1px solid #e3e4e5;
49073
49074
  border-radius: 12px;
49074
49075
  padding: 16px;
49075
49076
  font-size: 15px;
49077
+ font-family: Poppins, sans-serif;
49078
+ line-height: 1.5;
49079
+ letter-spacing: normal;
49076
49080
  resize: vertical;
49077
- background: #fff;
49081
+ background: transparent;
49082
+ color: #212121;
49083
+ position: relative;
49084
+ z-index: 1;
49085
+ box-sizing: border-box;
49086
+ outline: none;
49087
+ `;
49088
+ const GhostSuggestion = styled__default["default"].span`
49089
+ position: absolute;
49090
+ pointer-events: none;
49091
+ color: #b1b1b1;
49092
+ font-size: 15px;
49093
+ font-family: Poppins, sans-serif;
49094
+ line-height: 1.5;
49095
+ letter-spacing: normal;
49096
+ white-space: pre;
49097
+ z-index: 2;
49098
+ `;
49099
+ const MeasureSpan = styled__default["default"].span`
49100
+ position: absolute;
49101
+ visibility: hidden;
49102
+ white-space: pre;
49103
+ font-size: 15px;
49104
+ font-family: Poppins, sans-serif;
49105
+ line-height: 1.5;
49106
+ letter-spacing: normal;
49107
+ `;
49108
+ const SuggestionDropdown = styled__default["default"].ul`
49109
+ position: absolute;
49110
+ top: 100%;
49111
+ left: 0;
49112
+ z-index: 100;
49113
+ width: 100%;
49114
+ max-height: 240px;
49115
+ overflow-y: auto;
49116
+ list-style: none;
49117
+ margin: 4px 0 0 0;
49118
+ padding: 8px 0;
49119
+ background-color: #fff;
49120
+ border-radius: 8px;
49121
+ box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1);
49122
+ box-sizing: border-box;
49123
+ font-family: Poppins, sans-serif;
49124
+ font-size: 15px;
49125
+
49126
+ &::-webkit-scrollbar { width: 4px; }
49127
+ &::-webkit-scrollbar-track { background: #E8E8E8; border-radius: 5px; }
49128
+ &::-webkit-scrollbar-thumb { background: #D0D0D0; border-radius: 5px; }
49129
+ `;
49130
+ const SuggestionItem = styled__default["default"].li`
49131
+ padding: 8px 16px;
49132
+ cursor: pointer;
49078
49133
  color: #212121;
49134
+ font-size: 14px;
49135
+ font-weight: 400;
49136
+ transition: background-color 0.15s;
49137
+ background-color: ${props => props.$highlighted ? '#EDF6FF' : '#fff'};
49138
+
49139
+ &:hover {
49140
+ background-color: #EDF6FF;
49141
+ }
49079
49142
  `;
49080
49143
  const NegotiatedContainer = styled__default["default"].div`
49081
49144
  display: flex;
@@ -49088,6 +49151,155 @@ const NegotiatedContainer = styled__default["default"].div`
49088
49151
  margin-top: 8px;
49089
49152
  `;
49090
49153
 
49154
+ const MAX_VISIBLE_SUGGESTIONS = 4;
49155
+ const getMatchingSuggestions = (input, suggestions) => {
49156
+ const normalized = input.trim().toLowerCase().replace(/\s+/g, " ");
49157
+ if (!normalized || suggestions.length === 0) return [];
49158
+ const rank = (a, b) => b.frequency - a.frequency || (b.lastUsed || 0) - (a.lastUsed || 0);
49159
+ return suggestions.filter(s => {
49160
+ const norm = s.value.trim().toLowerCase().replace(/\s+/g, " ");
49161
+ return norm.startsWith(normalized) && norm !== normalized;
49162
+ }).sort(rank).slice(0, MAX_VISIBLE_SUGGESTIONS);
49163
+ };
49164
+ const BrandAutocomplete = ({
49165
+ value,
49166
+ onChange,
49167
+ suggestions = [],
49168
+ placeholder = "",
49169
+ maxLength = 200
49170
+ }) => {
49171
+ const measureRef = React$1.useRef(null);
49172
+ const dropdownRef = React$1.useRef(null);
49173
+ const blurTimeoutRef = React$1.useRef(null);
49174
+ const [textWidth, setTextWidth] = React$1.useState(0);
49175
+ const [highlightedIndex, setHighlightedIndex] = React$1.useState(-1);
49176
+ const [showDropdown, setShowDropdown] = React$1.useState(false);
49177
+ const matchingSuggestions = React$1.useMemo(() => getMatchingSuggestions(value, suggestions), [value, suggestions]);
49178
+ const activeSuggestion = highlightedIndex >= 0 ? matchingSuggestions[highlightedIndex] : matchingSuggestions[0] || null;
49179
+ const suggestionRemainder = activeSuggestion ? activeSuggestion.value.slice(value.length) : "";
49180
+
49181
+ // Measure typed text width after each change
49182
+ React$1.useEffect(() => {
49183
+ if (measureRef.current) {
49184
+ setTextWidth(measureRef.current.offsetWidth);
49185
+ }
49186
+ }, [value]);
49187
+
49188
+ // Close dropdown when no matches
49189
+ React$1.useEffect(() => {
49190
+ if (matchingSuggestions.length === 0) {
49191
+ setShowDropdown(false);
49192
+ setHighlightedIndex(-1);
49193
+ }
49194
+ }, [matchingSuggestions.length]);
49195
+
49196
+ // Scroll highlighted item into view
49197
+ React$1.useEffect(() => {
49198
+ if (highlightedIndex >= 0 && dropdownRef.current) {
49199
+ const items = dropdownRef.current.querySelectorAll("li");
49200
+ if (items[highlightedIndex]) {
49201
+ items[highlightedIndex].scrollIntoView({
49202
+ block: "nearest"
49203
+ });
49204
+ }
49205
+ }
49206
+ }, [highlightedIndex]);
49207
+
49208
+ // Cleanup blur timeout on unmount
49209
+ React$1.useEffect(() => {
49210
+ return () => {
49211
+ if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
49212
+ };
49213
+ }, []);
49214
+ const handleKeyDown = e => {
49215
+ const len = matchingSuggestions.length;
49216
+ if (e.key === "ArrowDown" && len > 0) {
49217
+ e.preventDefault();
49218
+ if (!showDropdown) {
49219
+ setShowDropdown(true);
49220
+ setHighlightedIndex(0);
49221
+ } else {
49222
+ setHighlightedIndex(prev => (prev + 1) % len);
49223
+ }
49224
+ return;
49225
+ }
49226
+ if (e.key === "ArrowUp" && len > 0 && showDropdown) {
49227
+ e.preventDefault();
49228
+ setHighlightedIndex(prev => prev <= 0 ? len - 1 : prev - 1);
49229
+ return;
49230
+ }
49231
+ if (e.key === "Enter" && showDropdown && highlightedIndex >= 0) {
49232
+ e.preventDefault();
49233
+ onChange(matchingSuggestions[highlightedIndex].value);
49234
+ setShowDropdown(false);
49235
+ setHighlightedIndex(-1);
49236
+ return;
49237
+ }
49238
+ if (e.key === "Escape" && showDropdown) {
49239
+ e.preventDefault();
49240
+ setShowDropdown(false);
49241
+ setHighlightedIndex(-1);
49242
+ return;
49243
+ }
49244
+ if (e.key === "Tab" && activeSuggestion && value.trim().length > 0) {
49245
+ e.preventDefault();
49246
+ onChange(activeSuggestion.value);
49247
+ setShowDropdown(false);
49248
+ setHighlightedIndex(-1);
49249
+ }
49250
+ };
49251
+ const handleChange = e => {
49252
+ const val = e.target.value;
49253
+ if (val.includes("$$")) return;
49254
+ const collapsed = val.replace(/ +/g, " ");
49255
+ onChange(collapsed);
49256
+ setHighlightedIndex(-1);
49257
+ setShowDropdown(collapsed.trim().length > 0);
49258
+ };
49259
+ const handleFocus = React$1.useCallback(() => {
49260
+ if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
49261
+ if (value.trim().length > 0 && matchingSuggestions.length > 0) {
49262
+ setShowDropdown(true);
49263
+ }
49264
+ }, [value, matchingSuggestions.length]);
49265
+ const handleBlur = React$1.useCallback(() => {
49266
+ blurTimeoutRef.current = setTimeout(() => {
49267
+ setShowDropdown(false);
49268
+ setHighlightedIndex(-1);
49269
+ }, 150);
49270
+ }, []);
49271
+ const handleSuggestionMouseDown = (e, suggestion) => {
49272
+ e.preventDefault();
49273
+ onChange(suggestion.value);
49274
+ setShowDropdown(false);
49275
+ setHighlightedIndex(-1);
49276
+ };
49277
+ const showGhost = activeSuggestion && value.length > 0;
49278
+ return /*#__PURE__*/React__default["default"].createElement(AutocompleteWrapper, null, /*#__PURE__*/React__default["default"].createElement(MeasureSpan, {
49279
+ ref: measureRef
49280
+ }, value), /*#__PURE__*/React__default["default"].createElement(NegotiatedTextarea, {
49281
+ value: value,
49282
+ onChange: handleChange,
49283
+ onKeyDown: handleKeyDown,
49284
+ onFocus: handleFocus,
49285
+ onBlur: handleBlur,
49286
+ placeholder: placeholder,
49287
+ maxLength: maxLength,
49288
+ required: true
49289
+ }), showGhost && /*#__PURE__*/React__default["default"].createElement(GhostSuggestion, {
49290
+ style: {
49291
+ top: 17,
49292
+ left: 17 + textWidth
49293
+ }
49294
+ }, suggestionRemainder), showDropdown && matchingSuggestions.length > 0 && /*#__PURE__*/React__default["default"].createElement(SuggestionDropdown, {
49295
+ ref: dropdownRef
49296
+ }, matchingSuggestions.map((suggestion, index) => /*#__PURE__*/React__default["default"].createElement(SuggestionItem, {
49297
+ key: suggestion.value,
49298
+ $highlighted: index === highlightedIndex,
49299
+ onMouseDown: e => handleSuggestionMouseDown(e, suggestion)
49300
+ }, suggestion.value))));
49301
+ };
49302
+
49091
49303
  const NewSubitem = ({
49092
49304
  packageObject,
49093
49305
  vendor,
@@ -49095,13 +49307,16 @@ const NewSubitem = ({
49095
49307
  addNewPackage,
49096
49308
  updateExistingPackage,
49097
49309
  componentText = "Scale",
49098
- itemAndPackage
49310
+ itemAndPackage,
49311
+ brandSuggestions = [],
49312
+ onBrandSaved
49099
49313
  }) => {
49100
49314
  const [negotiatedBrands, setNegotiatedBrands] = React$1.useState("");
49101
49315
  const [negotiatedComponent, setNegotiatedComponent] = React$1.useState(componentText);
49102
49316
  const [isPackageDuplicated, setIsPackageDuplicated] = React$1.useState(false);
49103
49317
  // Form state
49104
49318
  const [isApplyEnabled, setIsApplyEnabled] = React$1.useState(negotiatedBrands.trim().length > 2);
49319
+ const vendorSuggestions = React$1.useMemo(() => brandSuggestions.filter(s => s.vendor === vendor.name), [brandSuggestions, vendor.name]);
49105
49320
  React$1.useEffect(() => {
49106
49321
  if (!packageObject) return;
49107
49322
  if (!packageObject.brands) return;
@@ -49110,8 +49325,10 @@ const NewSubitem = ({
49110
49325
  }, [packageObject]);
49111
49326
  React$1.useEffect(() => {
49112
49327
  if (packageObject && packageObject.brands === negotiatedBrands) return;
49113
- setIsPackageDuplicated(itemAndPackage.some(obj => obj.name === vendor.name && obj.packages?.some(pkg => pkg.brands === negotiatedBrands)));
49114
- setIsApplyEnabled(negotiatedBrands.trim().length > 2 && !itemAndPackage.some(obj => obj.name === vendor.name && obj.packages?.some(pkg => pkg.brands === negotiatedBrands)));
49328
+ const normalizedInput = negotiatedBrands.trim().toLowerCase();
49329
+ const isDuplicate = itemAndPackage.some(obj => obj.packages?.some(pkg => pkg.brands?.trim().toLowerCase() === normalizedInput));
49330
+ setIsPackageDuplicated(isDuplicate);
49331
+ setIsApplyEnabled(negotiatedBrands.trim().length > 2 && !isDuplicate);
49115
49332
  }, [negotiatedBrands]);
49116
49333
  return /*#__PURE__*/React__default["default"].createElement(NewSubitemContainer, null, /*#__PURE__*/React__default["default"].createElement(Header, null, /*#__PURE__*/React__default["default"].createElement(BackButton, {
49117
49334
  onClick: onBack
@@ -49135,6 +49352,9 @@ const NewSubitem = ({
49135
49352
  } else {
49136
49353
  addNewPackage(vendor.name, negotiatedBrands, negotiatedComponent);
49137
49354
  }
49355
+ if (onBrandSaved) {
49356
+ onBrandSaved(negotiatedBrands, vendor.name);
49357
+ }
49138
49358
  },
49139
49359
  rightIcon: "none",
49140
49360
  size: "small",
@@ -49150,12 +49370,14 @@ const NewSubitem = ({
49150
49370
  style: {
49151
49371
  color: "red"
49152
49372
  }
49153
- }, "*")), /*#__PURE__*/React__default["default"].createElement(NegotiatedTextarea, {
49373
+ }, "*")), /*#__PURE__*/React__default["default"].createElement(BrandAutocomplete, {
49154
49374
  value: negotiatedBrands,
49155
- onChange: e => setNegotiatedBrands(e.target.value),
49156
- required: true,
49157
- placeholder: "Specify by text the participated brands, divided by commas"
49158
- }), isPackageDuplicated ? /*#__PURE__*/React__default["default"].createElement(ErrorLabel, null, "Package already exists for that vendor, Please enter a unique package.") : /*#__PURE__*/React__default["default"].createElement(ErrorLabel, null)), /*#__PURE__*/React__default["default"].createElement(NegotiatedContainer, null, /*#__PURE__*/React__default["default"].createElement(AddNegotiatedBrand, null, "Component ", /*#__PURE__*/React__default["default"].createElement("span", {
49375
+ onChange: val => setNegotiatedBrands(val),
49376
+ suggestions: vendorSuggestions,
49377
+ placeholder: "Specify by text the participated brands, divided by commas",
49378
+ maxLength: 200,
49379
+ hasError: isPackageDuplicated
49380
+ }), isPackageDuplicated ? /*#__PURE__*/React__default["default"].createElement(ErrorLabel, null, "Package already exists in the event, Please enter a unique package") : /*#__PURE__*/React__default["default"].createElement(ErrorLabel, null)), /*#__PURE__*/React__default["default"].createElement(NegotiatedContainer, null, /*#__PURE__*/React__default["default"].createElement(AddNegotiatedBrand, null, "Component ", /*#__PURE__*/React__default["default"].createElement("span", {
49159
49381
  style: {
49160
49382
  color: "red"
49161
49383
  }
@@ -57844,7 +58066,9 @@ const ItemManagerPanel = _ref => {
57844
58066
  onLastRowsReached = () => {},
57845
58067
  lastRowsThreshold = 3,
57846
58068
  onBackFromList = null,
57847
- onPackageAdded = null
58069
+ onPackageAdded = null,
58070
+ brandSuggestions = [],
58071
+ onBrandSaved = null
57848
58072
  } = _ref;
57849
58073
  const [screen, setScreen] = React$1.useState("initial");
57850
58074
  const [selectedVendor, setSelectedVendor] = React$1.useState(null);
@@ -57856,6 +58080,7 @@ const ItemManagerPanel = _ref => {
57856
58080
  const scrollWrapperRef = React$1.useRef(null);
57857
58081
  const headerRef = React$1.useRef(null);
57858
58082
  React$1.useEffect(() => {
58083
+ console.log("brandSuggestions", brandSuggestions);
57859
58084
  if (headerRef.current) {
57860
58085
  setHeaderHeight(headerRef.current.offsetHeight);
57861
58086
  }
@@ -58059,7 +58284,9 @@ const ItemManagerPanel = _ref => {
58059
58284
  updateExistingPackage: updateExistingPackage,
58060
58285
  isEditingExisting: isEditingExisting,
58061
58286
  onBack: () => setScreen("subitem"),
58062
- componentText: componentText
58287
+ componentText: componentText,
58288
+ brandSuggestions: brandSuggestions,
58289
+ onBrandSaved: onBrandSaved
58063
58290
  }));
58064
58291
  }
58065
58292
  if (screen === "list") {