@praxisui/core 9.0.40 → 9.0.42

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,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-08-30T07:25:27.035Z",
3
+ "generatedAt": "2026-08-30T12:51:40.847Z",
4
4
  "packageName": "@praxisui/core",
5
- "packageVersion": "9.0.40",
5
+ "packageVersion": "9.0.42",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 4,
@@ -40667,12 +40667,14 @@ class DynamicWidgetPageComponent {
40667
40667
  this.savePage(canonicalPage);
40668
40668
  }
40669
40669
  }
40670
- applyLayout(layout, grouping) {
40670
+ applyLayout(layout, grouping, deviceLayoutColumnsSelected = false) {
40671
40671
  this.layout = layout;
40672
40672
  this.canvas = undefined;
40673
40673
  this.grouping = grouping || [];
40674
40674
  const orientation = layout?.orientation || 'vertical';
40675
- const columns = orientation === 'columns' ? this.resolveColumns(layout) : 1;
40675
+ const columns = orientation === 'columns'
40676
+ ? this.resolveColumns(layout, deviceLayoutColumnsSelected)
40677
+ : 1;
40676
40678
  this.pageColumnCount = columns;
40677
40679
  this.gridTemplateColumns = `repeat(${columns}, minmax(0, 1fr))`;
40678
40680
  this.pageGap = layout?.gap || '16px';
@@ -40832,14 +40834,16 @@ class DynamicWidgetPageComponent {
40832
40834
  this.layoutAnnouncement = this.blockedCanvasAnnouncement(interaction.kind);
40833
40835
  this.applyTransientPagePreview(interaction.startPage, this.buildStateRuntime(interaction.startPage.state, interaction.startPage.context));
40834
40836
  }
40835
- resolveColumns(layout) {
40837
+ resolveColumns(layout, deviceLayoutColumnsSelected = false) {
40836
40838
  const base = Math.max(1, Number(layout?.columns) || 2);
40837
- const defaults = {
40838
- sm: 1,
40839
- md: Math.min(2, base),
40840
- lg: Math.min(3, base),
40841
- xl: base,
40842
- };
40839
+ const defaults = deviceLayoutColumnsSelected
40840
+ ? { sm: base, md: base, lg: base, xl: base }
40841
+ : {
40842
+ sm: 1,
40843
+ md: Math.min(2, base),
40844
+ lg: Math.min(3, base),
40845
+ xl: base,
40846
+ };
40843
40847
  const bp = layout?.breakpoints || {};
40844
40848
  const columns = {
40845
40849
  sm: Math.max(1, Number(bp.sm ?? defaults.sm)),
@@ -40928,7 +40932,7 @@ class DynamicWidgetPageComponent {
40928
40932
  this.applyCanvasLayout(effective.canvas, effective.layout, effective.grouping);
40929
40933
  }
40930
40934
  else {
40931
- this.applyLayout(effective.layout, effective.grouping);
40935
+ this.applyLayout(effective.layout, effective.grouping, effective.deviceLayoutColumnsSelected);
40932
40936
  }
40933
40937
  this.syncActiveTabs(effective.groups);
40934
40938
  this.mergedContext = this.mergeContext(pageDefinition?.context, this.context, runtime, {
@@ -40987,6 +40991,7 @@ class DynamicWidgetPageComponent {
40987
40991
  layout,
40988
40992
  canvas,
40989
40993
  grouping,
40994
+ deviceLayoutColumnsSelected: variant?.layout?.columns !== undefined,
40990
40995
  widgets: renderedWidgets,
40991
40996
  groups,
40992
40997
  };
@@ -41905,9 +41910,10 @@ class DynamicWidgetPageComponent {
41905
41910
  if (canvasItem) {
41906
41911
  return `${canvasItem.col} / span ${canvasItem.colSpan}`;
41907
41912
  }
41908
- if (!widget.renderSpan || widget.renderSpan <= 1)
41913
+ const renderSpan = Math.min(this.pageColumnCount, Math.max(1, Math.trunc(Number(widget.renderSpan) || 1)));
41914
+ if (renderSpan <= 1)
41909
41915
  return null;
41910
- return `span ${widget.renderSpan}`;
41916
+ return `span ${renderSpan}`;
41911
41917
  }
41912
41918
  widgetGridRow(widget) {
41913
41919
  const canvasItem = this.resolveRenderedCanvasItem(widget);
@@ -41935,7 +41941,76 @@ class DynamicWidgetPageComponent {
41935
41941
  }
41936
41942
  toPersistedCanonicalPage(page) {
41937
41943
  this.assertNoLegacyConnections(page);
41938
- return writeCompositionLinksToPersistedPage(page, page.composition?.links || []);
41944
+ const canonicalPage = this.stripDerivedPresetDefaults(page);
41945
+ return writeCompositionLinksToPersistedPage(canonicalPage, canonicalPage.composition?.links || []);
41946
+ }
41947
+ /**
41948
+ * Preset defaults are a runtime projection, not authored page state.
41949
+ *
41950
+ * Keeping an identical derived grouping in the persisted document would turn
41951
+ * semantic slot ids such as `master` and `detail-table` into apparent widget
41952
+ * references. The canonical page therefore keeps the preset id and slot
41953
+ * assignments while omitting defaults that the runtime can deterministically
41954
+ * rehydrate. Explicit overrides remain persisted.
41955
+ */
41956
+ stripDerivedPresetDefaults(page) {
41957
+ const canonical = this.clonePageDefinition(page);
41958
+ const preset = this.resolveLayoutPresetDefinition(canonical);
41959
+ if (!preset)
41960
+ return canonical;
41961
+ const layoutDelta = this.jsonObjectDelta(canonical.layout, preset.defaultLayout);
41962
+ if (layoutDelta) {
41963
+ canonical.layout = layoutDelta;
41964
+ }
41965
+ else {
41966
+ delete canonical.layout;
41967
+ }
41968
+ if (this.sameJsonStructure(canonical.grouping, preset.defaultGrouping)) {
41969
+ delete canonical.grouping;
41970
+ }
41971
+ if (canonical.themePreset === preset.defaultThemePreset) {
41972
+ delete canonical.themePreset;
41973
+ }
41974
+ return canonical;
41975
+ }
41976
+ jsonObjectDelta(value, defaults) {
41977
+ if (!value)
41978
+ return undefined;
41979
+ const delta = {};
41980
+ for (const [key, entry] of Object.entries(value)) {
41981
+ const defaultEntry = defaults?.[key];
41982
+ if (this.isJsonObject(entry) && this.isJsonObject(defaultEntry)) {
41983
+ const nestedDelta = this.jsonObjectDelta(entry, defaultEntry);
41984
+ if (nestedDelta)
41985
+ delta[key] = nestedDelta;
41986
+ continue;
41987
+ }
41988
+ if (!this.sameJsonStructure(entry, defaultEntry)) {
41989
+ delta[key] = this.stableJsonValue(entry);
41990
+ }
41991
+ }
41992
+ return Object.keys(delta).length ? delta : undefined;
41993
+ }
41994
+ isJsonObject(value) {
41995
+ return !!value && typeof value === 'object' && !Array.isArray(value);
41996
+ }
41997
+ sameJsonStructure(left, right) {
41998
+ return JSON.stringify(this.stableJsonValue(left)) ===
41999
+ JSON.stringify(this.stableJsonValue(right));
42000
+ }
42001
+ stableJsonValue(value) {
42002
+ if (Array.isArray(value)) {
42003
+ return value.map((entry) => this.stableJsonValue(entry));
42004
+ }
42005
+ if (this.isJsonObject(value)) {
42006
+ return Object.keys(value)
42007
+ .sort()
42008
+ .reduce((result, key) => {
42009
+ result[key] = this.stableJsonValue(value[key]);
42010
+ return result;
42011
+ }, {});
42012
+ }
42013
+ return value;
41939
42014
  }
41940
42015
  savePage(page) {
41941
42016
  const key = this.storageKey();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/core",
3
- "version": "9.0.40",
3
+ "version": "9.0.42",
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": "^21.0.0",
@@ -16835,6 +16835,20 @@ declare class DynamicWidgetPageComponent implements OnChanges, OnDestroy {
16835
16835
  private mergeClassNames;
16836
16836
  private resolveRenderedCanvasItem;
16837
16837
  private toPersistedCanonicalPage;
16838
+ /**
16839
+ * Preset defaults are a runtime projection, not authored page state.
16840
+ *
16841
+ * Keeping an identical derived grouping in the persisted document would turn
16842
+ * semantic slot ids such as `master` and `detail-table` into apparent widget
16843
+ * references. The canonical page therefore keeps the preset id and slot
16844
+ * assignments while omitting defaults that the runtime can deterministically
16845
+ * rehydrate. Explicit overrides remain persisted.
16846
+ */
16847
+ private stripDerivedPresetDefaults;
16848
+ private jsonObjectDelta;
16849
+ private isJsonObject;
16850
+ private sameJsonStructure;
16851
+ private stableJsonValue;
16838
16852
  private savePage;
16839
16853
  private loadPersistedPage;
16840
16854
  private storageKey;