@praxisui/core 8.0.0-beta.21 → 8.0.0-beta.22

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.
@@ -4396,7 +4396,7 @@ class GenericCrudService {
4396
4396
  return Number.isFinite(parsed) ? parsed : null;
4397
4397
  }
4398
4398
  tryParseDateMillis(value) {
4399
- if (value instanceof Date) {
4399
+ if (this.isDateValue(value)) {
4400
4400
  const ms = value.getTime();
4401
4401
  return Number.isNaN(ms) ? null : ms;
4402
4402
  }
@@ -4456,11 +4456,52 @@ class GenericCrudService {
4456
4456
  if (value === null || value === undefined) {
4457
4457
  return null;
4458
4458
  }
4459
- if (typeof value === 'string' && value.trim() === '') {
4460
- return null;
4459
+ if (this.isDateValue(value)) {
4460
+ return this.formatDateOnly(value);
4461
+ }
4462
+ if (typeof value === 'string') {
4463
+ const text = value.trim();
4464
+ if (text === '') {
4465
+ return null;
4466
+ }
4467
+ const numeric = this.tryParseLocalizedRangeNumber(text);
4468
+ if (numeric !== null) {
4469
+ return numeric;
4470
+ }
4471
+ return text;
4461
4472
  }
4462
4473
  return value;
4463
4474
  }
4475
+ isDateValue(value) {
4476
+ return Object.prototype.toString.call(value) === '[object Date]'
4477
+ && typeof value.getTime === 'function'
4478
+ && typeof value.getFullYear === 'function'
4479
+ && typeof value.getMonth === 'function'
4480
+ && typeof value.getDate === 'function';
4481
+ }
4482
+ formatDateOnly(value) {
4483
+ if (Number.isNaN(value.getTime())) {
4484
+ return value;
4485
+ }
4486
+ const year = value.getFullYear();
4487
+ const month = String(value.getMonth() + 1).padStart(2, '0');
4488
+ const day = String(value.getDate()).padStart(2, '0');
4489
+ return `${year}-${month}-${day}`;
4490
+ }
4491
+ tryParseLocalizedRangeNumber(text) {
4492
+ const compact = text.replace(/\s+/g, '');
4493
+ const numericText = compact.replace(/[^\d,.\-+]/g, '');
4494
+ if (!numericText) {
4495
+ return null;
4496
+ }
4497
+ const hasCurrencyMarker = /[R$€£¥]/.test(text);
4498
+ const hasDecimalComma = numericText.includes(',');
4499
+ const hasThousandsDot = /^[+-]?\d{1,3}(?:\.\d{3})+(?:,\d+)?$/.test(numericText);
4500
+ if (!hasCurrencyMarker && !hasDecimalComma && !hasThousandsDot) {
4501
+ return null;
4502
+ }
4503
+ return this.tryParseNumeric(numericText);
4504
+ }
4464
4505
  isRangeValue(value) {
4465
4506
  return value !== null && value !== undefined && !(typeof value === 'string' && value.trim() === '');
4466
4507
  }
@@ -8905,6 +8946,23 @@ function normalizeOptionSource(optionSource) {
8905
8946
  }
8906
8947
  return normalized;
8907
8948
  }
8949
+ function normalizeIconName(icon) {
8950
+ const value = String(icon ?? '').trim();
8951
+ return value.length ? value : undefined;
8952
+ }
8953
+ function normalizeIconPosition(position) {
8954
+ const value = String(position ?? '').trim().toLowerCase();
8955
+ if (!value) {
8956
+ return undefined;
8957
+ }
8958
+ if (['start', 'left', 'before', 'prefix', 'leading'].includes(value)) {
8959
+ return 'start';
8960
+ }
8961
+ if (['end', 'right', 'after', 'suffix', 'trailing'].includes(value)) {
8962
+ return 'end';
8963
+ }
8964
+ return undefined;
8965
+ }
8908
8966
  /**
8909
8967
  * Converte um FieldDefinition em FieldMetadata.
8910
8968
  *
@@ -8993,6 +9051,7 @@ function mapFieldDefinitionToMetadata(field) {
8993
9051
  'iconClass',
8994
9052
  'iconStyle',
8995
9053
  'iconFontSize',
9054
+ 'iconSize',
8996
9055
  'filterField',
8997
9056
  'dialog',
8998
9057
  'detailActionLabel',
@@ -9007,6 +9066,27 @@ function mapFieldDefinitionToMetadata(field) {
9007
9066
  metadata[prop] = value;
9008
9067
  }
9009
9068
  }
9069
+ const explicitPrefixIcon = normalizeIconName(field.prefixIcon);
9070
+ const explicitSuffixIcon = normalizeIconName(field.suffixIcon);
9071
+ const backendIcon = normalizeIconName(field.icon);
9072
+ const iconPosition = normalizeIconPosition(field.iconPosition);
9073
+ if (explicitPrefixIcon) {
9074
+ metadata.prefixIcon = explicitPrefixIcon;
9075
+ }
9076
+ if (explicitSuffixIcon) {
9077
+ metadata.suffixIcon = explicitSuffixIcon;
9078
+ }
9079
+ if (backendIcon && !explicitPrefixIcon && !explicitSuffixIcon) {
9080
+ if (iconPosition === 'end') {
9081
+ metadata.suffixIcon = backendIcon;
9082
+ }
9083
+ else {
9084
+ metadata.prefixIcon = backendIcon;
9085
+ }
9086
+ }
9087
+ if (iconPosition) {
9088
+ metadata.iconPosition = iconPosition;
9089
+ }
9010
9090
  const normalizedOptionSource = normalizeOptionSource(field.optionSource);
9011
9091
  if (normalizedOptionSource) {
9012
9092
  metadata.optionSource = normalizedOptionSource;
@@ -9045,9 +9125,6 @@ function mapFieldDefinitionToMetadata(field) {
9045
9125
  }
9046
9126
  }
9047
9127
  const hasOptionsFilterEndpoint = isOptionsFilterEndpoint(field.endpoint);
9048
- if (field.endpoint) {
9049
- metadata.endpoint = field.endpoint;
9050
- }
9051
9128
  const endpointPath = normalizeEndpoint$1(normalizedOptionSource?.resourcePath ?? field.resourcePath ?? field.endpoint);
9052
9129
  if (endpointPath) {
9053
9130
  // Canonicalize: only expose resourcePath; do not write legacy alias
@@ -32041,11 +32118,10 @@ function reconcileFormConfig(layout, serverDefs) {
32041
32118
  for (const [name, serverField] of serverByName) {
32042
32119
  const localField = localByName.get(name);
32043
32120
  if (localField) {
32044
- const base = buildBaseFormField(serverField);
32045
- merged.push(applyLocalCustomizations$1(base, localField));
32121
+ merged.push(applyLocalCustomizations$1(serverField, localField));
32046
32122
  }
32047
32123
  else {
32048
- merged.push(buildBaseFormField(serverField));
32124
+ merged.push(serverField);
32049
32125
  }
32050
32126
  }
32051
32127
  // Orphans: preserve explicit local fields; hide legacy schema fields that no
package/index.d.ts CHANGED
@@ -4854,6 +4854,9 @@ declare class GenericCrudService<T, ID extends string | number = string | number
4854
4854
  private resolveRangeAliases;
4855
4855
  private findExistingKey;
4856
4856
  private normalizeRangeBound;
4857
+ private isDateValue;
4858
+ private formatDateOnly;
4859
+ private tryParseLocalizedRangeNumber;
4857
4860
  private isRangeValue;
4858
4861
  private isPlainObject;
4859
4862
  private updateRangeFieldHints;
@@ -6391,8 +6394,13 @@ interface MaterialDateRangeMetadata extends FieldMetadata {
6391
6394
  * - `confirm`: keeps selection as draft and only commits on explicit confirmation
6392
6395
  */
6393
6396
  inlineQuickPresetsApplyMode?: 'auto' | 'confirm';
6394
- /** Position of shortcuts sidebar relative to the form field. */
6395
- shortcutsPosition?: 'left' | 'right';
6397
+ /**
6398
+ * Preferred position of shortcuts panel relative to the form field.
6399
+ * Defaults to `auto`, which tries a viewport-safe below placement before
6400
+ * side placements. Explicit `left`/`right` remain preferences and may fall
6401
+ * back when there is not enough viewport space.
6402
+ */
6403
+ shortcutsPosition?: 'auto' | 'below' | 'left' | 'right';
6396
6404
  /** Apply immediately when clicking a shortcut. Defaults to true. */
6397
6405
  applyOnShortcutClick?: boolean;
6398
6406
  /** Timezone identifier (e.g., 'America/Sao_Paulo') for normalization. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/core",
3
- "version": "8.0.0-beta.21",
3
+ "version": "8.0.0-beta.22",
4
4
  "description": "Core library for Praxis UI Workspace: types, tokens, services and utilities shared across @praxisui/* packages.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^20.0.0",