@seedgrid/fe-components 2026.9.4 → 2026.9.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.
@@ -1 +1 @@
1
- {"version":3,"file":"SgInputDate.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputDate.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKnE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG;IAC9D,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAuBF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CA0JlD"}
1
+ {"version":3,"file":"SgInputDate.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputDate.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKnE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,GAAG;IAC9D,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAoCF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CA0JlD"}
@@ -29,6 +29,18 @@ function parseDateValue(value) {
29
29
  return null;
30
30
  return date;
31
31
  }
32
+ /**
33
+ * Teto do widget quando o consumidor nao informa `maxDate`.
34
+ *
35
+ * O <input type="date"> aceita ano de ate 6 digitos (o calendario do HTML vai ate
36
+ * 275760), entao sem `max` o campo aceita "202699" no lugar de "2026". Com um `max`
37
+ * de ano de 4 digitos o navegador contem o segmento em 4.
38
+ *
39
+ * Vale so' para o atributo HTML: a validacao continua usando os limites que o
40
+ * consumidor pediu, para nenhuma mensagem de erro citar um 31/12/9999 que ninguem
41
+ * escolheu.
42
+ */
43
+ const WIDGET_MAX_DATE = "9999-12-31";
32
44
  export function SgInputDate(props) {
33
45
  const i18n = useComponentsI18n();
34
46
  const isDark = useDarkFlag();
@@ -86,7 +98,7 @@ export function SgInputDate(props) {
86
98
  ...inputProps,
87
99
  placeholder: showStaticLabel ? " " : (inputProps?.placeholder ?? rest.hintText ?? labelText),
88
100
  min: minDateValue,
89
- max: maxDateValue,
101
+ max: maxDateValue ?? WIDGET_MAX_DATE,
90
102
  readOnly: inputProps?.readOnly,
91
103
  onChange: (event) => {
92
104
  setHasInteracted(true);
@@ -1 +1 @@
1
- {"version":3,"file":"SgPeriodSelector.d.ts","sourceRoot":"","sources":["../../src/inputs/SgPeriodSelector.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SgPeriodSelector.d.ts","sourceRoot":"","sources":["../../src/inputs/SgPeriodSelector.tsx"],"names":[],"mappings":"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"}
@@ -296,37 +296,51 @@ export function buildPeriodOptions(config, locale = "pt-BR") {
296
296
  /* ------------------------------------------------------------------ */
297
297
  /* Componente */
298
298
  /* ------------------------------------------------------------------ */
299
- function toIsoDate(d) {
300
- if (!d)
301
- return "";
302
- const year = d.getFullYear();
303
- const month = String(d.getMonth() + 1).padStart(2, "0");
304
- const day = String(d.getDate()).padStart(2, "0");
305
- return `${year}-${month}-${day}`;
306
- }
299
+ /**
300
+ * Converte o valor cru do <input type="date"> (ISO yyyy-MM-dd) em Date local.
301
+ *
302
+ * O input nativo emite um change a cada digito do ano, entao "2026" chega aqui
303
+ * antes como "0002", "0020" e "0202". Esses anos incompletos sao recusados, e o
304
+ * ano completo passa por setFullYear para escapar da regra legada do JS que
305
+ * mapeia ano 0..99 para 1900+ano (new Date(2, 8, 19) => 1902-09-19).
306
+ */
307
307
  function parseIsoDate(value) {
308
- if (!value)
308
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
309
+ if (!match)
309
310
  return null;
310
- const [y, m, d] = value.split("-").map((part) => Number(part));
311
- if (!y || !m || !d)
311
+ const year = Number(match[1]);
312
+ const month = Number(match[2]);
313
+ const day = Number(match[3]);
314
+ if (year < 1000 || month < 1 || month > 12 || day < 1 || day > 31)
312
315
  return null;
313
- return new Date(y, m - 1, d);
316
+ const date = new Date(year, month - 1, day);
317
+ date.setFullYear(year);
318
+ return Number.isNaN(date.getTime()) ? null : date;
314
319
  }
315
320
  function SgPeriodSelectorBase(props) {
316
321
  const { id = "sg-period-selector", label, value, onChange, permitPast = true, permitCurrent = true, permitFuture = true, permitAll = true, allowCustomPeriod = true, locale = "pt-BR", disabled, required, minDate, maxDate, referenceDate, className, error } = props;
317
322
  const isControlled = value !== undefined;
318
323
  const [internalPreset, setInternalPreset] = React.useState(value ?? null);
319
324
  const selectedPreset = isControlled ? value ?? null : internalPreset;
320
- const [customStart, setCustomStart] = React.useState(null);
321
- const [customEnd, setCustomEnd] = React.useState(null);
325
+ // Guardamos a string crua do input (ISO ou parcial), nunca um Date reformatado:
326
+ // devolver ao input um texto diferente do digitado reinicia o segmento em foco
327
+ // e impede o usuario de terminar de digitar o ano.
328
+ const [customStart, setCustomStart] = React.useState("");
329
+ const [customEnd, setCustomEnd] = React.useState("");
322
330
  const options = React.useMemo(() => buildPeriodOptions({ permitAll, allowCustomPeriod, permitCurrent, permitFuture, permitPast }, locale), [permitAll, allowCustomPeriod, permitCurrent, permitFuture, permitPast, locale]);
323
331
  const resolveOptions = React.useMemo(() => ({ minDate, maxDate, locale }), [minDate, maxDate, locale]);
324
- const emitCustom = React.useCallback((start, end) => {
332
+ const emitCustom = React.useCallback((startIso, endIso) => {
333
+ // Enquanto a data estiver incompleta o parse devolve null: melhor emitir
334
+ // "sem limite" do que uma data de ano 0002 no meio da digitacao.
335
+ const startDate = parseIsoDate(startIso);
336
+ const endDate = parseIsoDate(endIso);
337
+ startDate?.setHours(0, 0, 0, 0);
338
+ endDate?.setHours(23, 59, 59, 999);
325
339
  onChange?.({
326
340
  preset: PeriodPreset.CUSTOM,
327
341
  label: periodPresetLabel(PeriodPreset.CUSTOM, locale),
328
- startDate: start ? new Date(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, 0, 0) : null,
329
- endDate: end ? new Date(end.getFullYear(), end.getMonth(), end.getDate(), 23, 59, 59, 999) : null
342
+ startDate,
343
+ endDate
330
344
  });
331
345
  }, [locale, onChange]);
332
346
  const handleValueChange = React.useCallback((raw) => {
@@ -346,14 +360,12 @@ function SgPeriodSelectorBase(props) {
346
360
  onChange?.(resolvePeriod(preset, referenceDate ?? new Date(), resolveOptions));
347
361
  }, [customEnd, customStart, emitCustom, isControlled, onChange, referenceDate, resolveOptions]);
348
362
  const showCustomRange = allowCustomPeriod && selectedPreset === PeriodPreset.CUSTOM;
349
- return (_jsxs("div", { className: cn("w-full max-w-[18rem]", className), children: [_jsx(SgCombobox, { id: id, label: label, source: options, value: selectedPreset ?? null, grouped: true, openOnFocus: true, enabled: disabled ? false : undefined, required: required, error: error, renderGroupHeader: (group) => group ? (_jsx("div", { className: "mt-2 border-b border-border pb-1.5 text-center text-[11px] font-bold uppercase tracking-wider text-muted-foreground", children: group })) : null, onValueChange: handleValueChange }), showCustomRange ? (_jsxs("div", { className: "mt-2 grid grid-cols-1 gap-2", children: [_jsx(SgInputDate, { id: `${id}-custom-start`, inputProps: { value: toIsoDate(customStart) }, minDate: minDate, maxDate: maxDate, enabled: disabled ? false : undefined, onChange: (next) => {
350
- const parsed = parseIsoDate(next);
351
- setCustomStart(parsed);
352
- emitCustom(parsed, customEnd);
353
- } }), _jsx(SgInputDate, { id: `${id}-custom-end`, inputProps: { value: toIsoDate(customEnd) }, minDate: minDate, maxDate: maxDate, enabled: disabled ? false : undefined, onChange: (next) => {
354
- const parsed = parseIsoDate(next);
355
- setCustomEnd(parsed);
356
- emitCustom(customStart, parsed);
363
+ return (_jsxs("div", { className: cn("w-full max-w-[18rem]", className), children: [_jsx(SgCombobox, { id: id, label: label, source: options, value: selectedPreset ?? null, grouped: true, openOnFocus: true, enabled: disabled ? false : undefined, required: required, error: error, renderGroupHeader: (group) => group ? (_jsx("div", { className: "mt-2 border-b border-border pb-1.5 text-center text-[11px] font-bold uppercase tracking-wider text-muted-foreground", children: group })) : null, onValueChange: handleValueChange }), showCustomRange ? (_jsxs("div", { className: "mt-2 grid grid-cols-1 gap-2", children: [_jsx(SgInputDate, { id: `${id}-custom-start`, inputProps: { value: customStart }, minDate: minDate, maxDate: maxDate, enabled: disabled ? false : undefined, onChange: (next) => {
364
+ setCustomStart(next);
365
+ emitCustom(next, customEnd);
366
+ } }), _jsx(SgInputDate, { id: `${id}-custom-end`, inputProps: { value: customEnd }, minDate: minDate, maxDate: maxDate, enabled: disabled ? false : undefined, onChange: (next) => {
367
+ setCustomEnd(next);
368
+ emitCustom(customStart, next);
357
369
  } })] })) : null] }));
358
370
  }
359
371
  export function SgPeriodSelector(props) {