pcm-shared-components 2.1.392 → 2.1.394

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.
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { TextField, Icon, IconButton, Button, Paper, Typography, InputAdornment, MenuItem, ToggleButton, ToggleButtonGroup, Checkbox, ListItemText, Chip, Alert, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material';
4
4
  import { ThemeProvider } from '@mui/system';
@@ -195,6 +195,42 @@ export const AnimalVehicleDetailsEditor = props => {
195
195
  setPendingFocusIndex(idx);
196
196
  };
197
197
  const selectedItem = items[selectedIndex];
198
+
199
+ // Ref registry for each field's label element, keyed by field.key -- rebuilt every render (a
200
+ // field can be removed/reordered), read by the layout effect below to measure whether a label
201
+ // actually wrapped onto a second line at its current column width.
202
+ const labelRefs = useRef(new Map());
203
+ const [wrappedKeys, setWrappedKeys] = useState(() => new Set());
204
+
205
+ // A label long enough to wrap onto a second line at half-column width throws that field's
206
+ // control out of vertical alignment with whatever ends up paired next to it -- a one-line label
207
+ // and a two-line label start their inputs at different heights even though both cells are the
208
+ // same width. Admin-typed labels are free text up to 100 characters of wildly different letter
209
+ // widths, so a character-count cutoff would either wrongly wrap a short-but-wide label or miss a
210
+ // long-but-narrow one; this measures the ACTUAL rendered height of every label after each paint
211
+ // instead and promotes any field whose label wrapped to full width too, same treatment as a
212
+ // type-forced or orphaned field.
213
+ //
214
+ // Re-runs whenever the wrapped set itself changes (not just when `fieldConfig` changes), because
215
+ // promoting one field to full width re-pairs its neighbors, which can occasionally make a
216
+ // DIFFERENT field's label newly wrap (or stop wrapping) at its new column width. Safe from an
217
+ // infinite loop: promotions only ever add width, never remove it, so this converges in at most a
218
+ // few passes, and the state setter bails out (no re-render) the moment a pass finds no change.
219
+ useLayoutEffect(() => {
220
+ const nextWrapped = new Set();
221
+ labelRefs.current.forEach((el, fieldKey) => {
222
+ if (!el) return;
223
+ const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 0;
224
+ if (lineHeight > 0 && el.offsetHeight > lineHeight * 1.4) {
225
+ nextWrapped.add(fieldKey);
226
+ }
227
+ });
228
+ setWrappedKeys(prev => {
229
+ if (prev.size === nextWrapped.size && [...prev].every(k => nextWrapped.has(k))) return prev;
230
+ return nextWrapped;
231
+ });
232
+ }, [fieldConfig, wrappedKeys]);
233
+ const isFullWidthField = f => ['select', 'textarea', 'select_multiple'].includes(f.type) || wrappedKeys.has(f.key);
198
234
  return /*#__PURE__*/React.createElement(ThemeProvider, {
199
235
  theme: defaultTheme
200
236
  }, /*#__PURE__*/React.createElement("div", {
@@ -302,7 +338,7 @@ export const AnimalVehicleDetailsEditor = props => {
302
338
  }, /*#__PURE__*/React.createElement(DeleteOutlineIcon, {
303
339
  fontSize: "small"
304
340
  }))), (() => {
305
- const pairableFields = fieldConfig.filter(f => !['select', 'textarea', 'select_multiple'].includes(f.type));
341
+ const pairableFields = fieldConfig.filter(f => !isFullWidthField(f));
306
342
  const orphanField = pairableFields.length % 2 === 1 ? pairableFields[pairableFields.length - 1] : null;
307
343
  return /*#__PURE__*/React.createElement("div", {
308
344
  ref: fieldsContainerRef,
@@ -327,7 +363,7 @@ export const AnimalVehicleDetailsEditor = props => {
327
363
  // extra length was long enough to wrap onto a second line in a narrow column,
328
364
  // throwing that field's input out of vertical alignment with its paired neighbor.
329
365
  const labelText = field.required ? `${field.label} *` : field.label;
330
- const wrapperClassName = ['select', 'textarea', 'select_multiple'].includes(field.type) || field === orphanField ? 'col-span-full' : undefined;
366
+ const wrapperClassName = isFullWidthField(field) || field === orphanField ? 'col-span-full' : undefined;
331
367
  let control;
332
368
  if (showAsDrifted) {
333
369
  // Generic stringify -- this renders whatever type the field used to be, which
@@ -523,6 +559,9 @@ export const AnimalVehicleDetailsEditor = props => {
523
559
  key: revealKey,
524
560
  "data-field-invalid": showError ? 'true' : undefined
525
561
  }, /*#__PURE__*/React.createElement(Typography, {
562
+ ref: el => {
563
+ if (el) labelRefs.current.set(field.key, el);else labelRefs.current.delete(field.key);
564
+ },
526
565
  variant: "body2",
527
566
  sx: {
528
567
  fontWeight: 500,
@@ -2524,7 +2524,8 @@
2524
2524
  "width": "Width",
2525
2525
  "max_adult": "Max Adults",
2526
2526
  "max_children": "Max Children",
2527
- "max_animal": "Max Animals"
2527
+ "max_animal": "Max Animals",
2528
+ "animal_fields": "Animal Fields"
2528
2529
  }
2529
2530
  },
2530
2531
  "lot_selection": {
@@ -4505,7 +4506,7 @@
4505
4506
  "add_animal_details": "Add animal details",
4506
4507
  "add_details": "Add details",
4507
4508
  "animal_details": "Animal details",
4508
- "counts": "Party",
4509
+ "counts": "Occupants",
4509
4510
  "details": "Details",
4510
4511
  "optional_tip": "Every field on this page is optional. Leave anything blank and press Continue when you're done. You can also come back later to fill them in.",
4511
4512
  "skip_details": "Skip details",
@@ -2524,7 +2524,8 @@
2524
2524
  "width": "Ancho",
2525
2525
  "max_adult": "Máximo de adultos",
2526
2526
  "max_children": "Máximo de niños",
2527
- "max_animal": "Máximo de animales"
2527
+ "max_animal": "Máximo de animales",
2528
+ "animal_fields": "Campos para animales"
2528
2529
  }
2529
2530
  },
2530
2531
  "lot_selection": {
@@ -4505,7 +4506,7 @@
4505
4506
  "add_animal_details": "Agregar detalles del animal",
4506
4507
  "add_details": "Agregar detalles",
4507
4508
  "animal_details": "Detalles del animal",
4508
- "counts": "Grupo",
4509
+ "counts": "Ocupantes",
4509
4510
  "details": "Detalles",
4510
4511
  "optional_tip": "Todos los campos de esta página son opcionales. Deje en blanco lo que quiera y presione Continuar cuando termine. También puede volver más tarde para completarlos.",
4511
4512
  "skip_details": "Omitir detalles",
@@ -2524,7 +2524,8 @@
2524
2524
  "width": "Largeur",
2525
2525
  "max_adult": "Adultes max",
2526
2526
  "max_children": "Enfants max",
2527
- "max_animal": "Animaux max"
2527
+ "max_animal": "Animaux max",
2528
+ "animal_fields": "Champs pour les animaux"
2528
2529
  }
2529
2530
  },
2530
2531
  "lot_selection": {
@@ -4505,7 +4506,7 @@
4505
4506
  "add_animal_details": "Ajouter les détails de l'animal",
4506
4507
  "add_details": "Ajouter les détails",
4507
4508
  "animal_details": "Détails de l'animal",
4508
- "counts": "Groupe",
4509
+ "counts": "Occupants",
4509
4510
  "details": "Détails",
4510
4511
  "optional_tip": "Tous les champs de cette page sont facultatifs. Laissez vide ce que vous souhaitez et appuyez sur Continuer lorsque vous avez terminé. Vous pourrez aussi revenir plus tard pour les compléter.",
4511
4512
  "skip_details": "Ignorer les détails",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pcm-shared-components",
3
- "version": "2.1.392",
3
+ "version": "2.1.394",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "babel": {