@ng-prism/core 22.0.0-beta.2 → 22.0.0-beta.4

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.
@@ -27,6 +27,8 @@ export declare class PrismRendererComponent {
27
27
  readonly activeOverlay: import("@angular/core").WritableSignal<Type<unknown> | null>;
28
28
  /** Identifier of the currently rendered component/variant (for audit tooling / e2e). */
29
29
  protected readonly renderedKey: import("@angular/core").Signal<string | null>;
30
+ /** Resolved canvas layout for the active variant — variant overrides component config; defaults to 'fit'. */
31
+ protected readonly canvasLayout: import("@angular/core").Signal<import("../../shared/canvas-layout.type.js").CanvasLayout>;
30
32
  protected readonly overlayInputs: {
31
33
  rendererService: PrismRendererService;
32
34
  };
@@ -1 +1 @@
1
- {"version":3,"file":"prism-renderer.component.d.ts","sourceRoot":"","sources":["../../../src/app/renderer/prism-renderer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,QAAQ,EAER,KAAK,IAAI,EAIV,MAAM,eAAe,CAAC;AAYvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAGjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;;AAIhF,qBA2Ia,sBAAsB;IACjC,SAAS,CAAC,QAAQ,CAAC,IAAI,OAAQ;IAC/B,SAAS,CAAC,QAAQ,CAAC,iBAAiB,yBAAkC;IACtE,SAAS,CAAC,QAAQ,CAAC,eAAe,uBAAgC;IAClE,SAAS,CAAC,QAAQ,CAAC,aAAa,qBAA8B;IAC9D,SAAS,CAAC,QAAQ,CAAC,SAAS,wBAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAE3B;IAEH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8B;IAE5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;IACH,OAAO,CAAC,YAAY,CAAsC;IAC1D,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,oBAAoB,CAChB;IACZ,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoC;IACjE,QAAQ,CAAC,aAAa,+DAAsC;IAC5D,wFAAwF;IACxF,SAAS,CAAC,QAAQ,CAAC,WAAW,gDAQ3B;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa;;MAA6C;IAC7E,SAAS,CAAC,QAAQ,CAAC,eAAe,yFAG/B;;IA0FH,OAAO,CAAC,eAAe;IA6FvB,OAAO,CAAC,OAAO;yCAlOJ,sBAAsB;2CAAtB,sBAAsB;CAgPlC"}
1
+ {"version":3,"file":"prism-renderer.component.d.ts","sourceRoot":"","sources":["../../../src/app/renderer/prism-renderer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,QAAQ,EAER,KAAK,IAAI,EAIV,MAAM,eAAe,CAAC;AAYvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAGjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;;AAIhF,qBA8Ia,sBAAsB;IACjC,SAAS,CAAC,QAAQ,CAAC,IAAI,OAAQ;IAC/B,SAAS,CAAC,QAAQ,CAAC,iBAAiB,yBAAkC;IACtE,SAAS,CAAC,QAAQ,CAAC,eAAe,uBAAgC;IAClE,SAAS,CAAC,QAAQ,CAAC,aAAa,qBAA8B;IAC9D,SAAS,CAAC,QAAQ,CAAC,SAAS,wBAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAE3B;IAEH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8B;IAE5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;IACH,OAAO,CAAC,YAAY,CAAsC;IAC1D,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,oBAAoB,CAChB;IACZ,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoC;IACjE,QAAQ,CAAC,aAAa,+DAAsC;IAC5D,wFAAwF;IACxF,SAAS,CAAC,QAAQ,CAAC,WAAW,gDAQ3B;IACH,6GAA6G;IAC7G,SAAS,CAAC,QAAQ,CAAC,YAAY,4FAQ5B;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa;;MAA6C;IAC7E,SAAS,CAAC,QAAQ,CAAC,eAAe,yFAG/B;;IA0FH,OAAO,CAAC,eAAe;IA6FvB,OAAO,CAAC,OAAO;yCA5OJ,sBAAsB;2CAAtB,sBAAsB;CA0PlC"}
@@ -60,6 +60,15 @@ export class PrismRendererComponent {
60
60
  return `${comp.meta.className}:${this.rendererService.activeVariantIndex()}`;
61
61
  }, /* @ts-ignore */
62
62
  ...(ngDevMode ? [{ debugName: "renderedKey" }] : /* istanbul ignore next */ []));
63
+ /** Resolved canvas layout for the active variant — variant overrides component config; defaults to 'fit'. */
64
+ canvasLayout = computed(() => {
65
+ const comp = this.navigationService.activeComponent();
66
+ if (!comp)
67
+ return 'fit';
68
+ const variant = comp.meta.showcaseConfig.variants?.[this.rendererService.activeVariantIndex()];
69
+ return variant?.canvasLayout ?? comp.meta.showcaseConfig.canvasLayout ?? 'fit';
70
+ }, /* @ts-ignore */
71
+ ...(ngDevMode ? [{ debugName: "canvasLayout" }] : /* istanbul ignore next */ []));
63
72
  overlayInputs = { rendererService: this.rendererService };
64
73
  overlayInjector = computed(() => {
65
74
  const panelInjector = this.panelService.activePanelInjector();
@@ -220,7 +229,7 @@ export class PrismRendererComponent {
220
229
  i0.ɵɵviewQuerySignal(ctx.outlet, _c0, 5, ViewContainerRef);
221
230
  } if (rf & 2) {
222
231
  i0.ɵɵqueryAdvance();
223
- } }, decls: 11, vars: 9, consts: [["outlet", ""], [1, "prism-canvas-stage"], [1, "canvas-badges"], [1, "c-badge"], [1, "stage-crosshair"], [1, "demo-wrap"], [4, "ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector"]], template: function PrismRendererComponent_Template(rf, ctx) { if (rf & 1) {
232
+ } }, decls: 11, vars: 10, consts: [["outlet", ""], [1, "prism-canvas-stage"], [1, "canvas-badges"], [1, "c-badge"], [1, "stage-crosshair"], [1, "demo-wrap"], [4, "ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector"]], template: function PrismRendererComponent_Template(rf, ctx) { if (rf & 1) {
224
233
  i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "span", 3);
225
234
  i0.ɵɵtext(3);
226
235
  i0.ɵɵelementEnd()();
@@ -237,12 +246,12 @@ export class PrismRendererComponent {
237
246
  i0.ɵɵclassProp("visible", ctx.canvasService.guides());
238
247
  i0.ɵɵadvance(3);
239
248
  i0.ɵɵstyleProp("--zoom", ctx.canvasService.zoom());
240
- i0.ɵɵattribute("data-prism-rendered", ctx.renderedKey());
249
+ i0.ɵɵattribute("data-prism-rendered", ctx.renderedKey())("data-canvas-layout", ctx.canvasLayout());
241
250
  i0.ɵɵadvance(3);
242
251
  i0.ɵɵconditional(ctx.activeOverlay() ? 10 : -1);
243
252
  } }, dependencies: [PrismCanvasRulersComponent,
244
253
  PrismCanvasBgPillComponent,
245
- NgComponentOutlet], styles: ["[_nghost-%COMP%] { display: block; min-height: 0; flex: 1; }\n\n .prism-canvas-stage[_ngcontent-%COMP%] {\n position: relative;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 32px;\n min-height: 200px;\n height: 100%;\n background-color: var(--prism-bg-surface);\n background-image: radial-gradient(circle, var(--prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n transition: filter var(--dur-base);\n --prism-canvas-overlay-top: 12px;\n --prism-canvas-overlay-inline: 20px;\n }\n .prism-canvas-stage[data-rulers][_ngcontent-%COMP%] {\n --prism-canvas-overlay-top: 28px;\n --prism-canvas-overlay-inline: 28px;\n }\n\n .prism-canvas-stage[data-bg=\"plain\"][_ngcontent-%COMP%] {\n background-image: none;\n }\n .prism-canvas-stage[data-bg=\"light\"][_ngcontent-%COMP%] {\n background-color: var(--prism-void-light, #f7f5fc);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary-from) 15%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"dark\"][_ngcontent-%COMP%] {\n background-color: var(--prism-void-dark, #07050f);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary) 18%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"checker\"][_ngcontent-%COMP%] {\n background-image:\n linear-gradient(45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n\n .stage-crosshair[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--dur-base);\n }\n .stage-crosshair.visible[_ngcontent-%COMP%] { opacity: 1; }\n .stage-crosshair[_ngcontent-%COMP%]::before, \n .stage-crosshair[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n background: color-mix(in srgb, var(--prism-primary) 20%, transparent);\n }\n .stage-crosshair[_ngcontent-%COMP%]::before { left: 0; right: 0; top: 50%; height: 1px; }\n .stage-crosshair[_ngcontent-%COMP%]::after { top: 0; bottom: 0; left: 50%; width: 1px; }\n\n .canvas-badges[_ngcontent-%COMP%] {\n position: absolute;\n top: var(--prism-canvas-overlay-top);\n left: var(--prism-canvas-overlay-inline);\n display: flex;\n gap: 6px;\n pointer-events: none;\n transition: top var(--dur-base), left var(--dur-base);\n }\n .c-badge[_ngcontent-%COMP%] {\n font-family: var(--font-mono);\n font-size: var(--fs-xs);\n padding: 3px 7px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--prism-bg-elevated) 90%, transparent);\n border: 1px solid var(--prism-border);\n color: var(--prism-text-muted);\n backdrop-filter: blur(8px);\n }\n\n .demo-wrap[_ngcontent-%COMP%] {\n position: relative;\n display: block;\n width: 100%;\n max-width: 800px;\n text-align: center;\n transform: scale(var(--zoom, 1));\n transition: transform 0.18s;\n }"] });
254
+ NgComponentOutlet], styles: ["[_nghost-%COMP%] { display: block; min-height: 0; flex: 1; }\n\n .prism-canvas-stage[_ngcontent-%COMP%] {\n position: relative;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 32px;\n min-height: 200px;\n height: 100%;\n background-color: var(--prism-bg-surface);\n background-image: radial-gradient(circle, var(--prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n transition: filter var(--dur-base);\n --prism-canvas-overlay-top: 12px;\n --prism-canvas-overlay-inline: 20px;\n }\n .prism-canvas-stage[data-rulers][_ngcontent-%COMP%] {\n --prism-canvas-overlay-top: 28px;\n --prism-canvas-overlay-inline: 28px;\n }\n\n .prism-canvas-stage[data-bg=\"plain\"][_ngcontent-%COMP%] {\n background-image: none;\n }\n .prism-canvas-stage[data-bg=\"light\"][_ngcontent-%COMP%] {\n background-color: var(--prism-void-light, #f7f5fc);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary-from) 15%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"dark\"][_ngcontent-%COMP%] {\n background-color: var(--prism-void-dark, #07050f);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary) 18%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"checker\"][_ngcontent-%COMP%] {\n background-image:\n linear-gradient(45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n\n .stage-crosshair[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--dur-base);\n }\n .stage-crosshair.visible[_ngcontent-%COMP%] { opacity: 1; }\n .stage-crosshair[_ngcontent-%COMP%]::before, \n .stage-crosshair[_ngcontent-%COMP%]::after {\n content: '';\n position: absolute;\n background: color-mix(in srgb, var(--prism-primary) 20%, transparent);\n }\n .stage-crosshair[_ngcontent-%COMP%]::before { left: 0; right: 0; top: 50%; height: 1px; }\n .stage-crosshair[_ngcontent-%COMP%]::after { top: 0; bottom: 0; left: 50%; width: 1px; }\n\n .canvas-badges[_ngcontent-%COMP%] {\n position: absolute;\n top: var(--prism-canvas-overlay-top);\n left: var(--prism-canvas-overlay-inline);\n display: flex;\n gap: 6px;\n pointer-events: none;\n transition: top var(--dur-base), left var(--dur-base);\n }\n .c-badge[_ngcontent-%COMP%] {\n font-family: var(--font-mono);\n font-size: var(--fs-xs);\n padding: 3px 7px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--prism-bg-elevated) 90%, transparent);\n border: 1px solid var(--prism-border);\n color: var(--prism-text-muted);\n backdrop-filter: blur(8px);\n }\n\n .demo-wrap[_ngcontent-%COMP%] {\n position: relative;\n display: inline-block;\n transform: scale(var(--zoom, 1));\n transition: transform 0.18s;\n }\n .demo-wrap[data-canvas-layout=\"stretch\"][_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n max-width: 800px;\n }"] });
246
255
  }
247
256
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PrismRendererComponent, [{
248
257
  type: Component,
@@ -272,6 +281,7 @@ export class PrismRendererComponent {
272
281
  class="demo-wrap"
273
282
  [style.--zoom]="canvasService.zoom()"
274
283
  [attr.data-prism-rendered]="renderedKey()"
284
+ [attr.data-canvas-layout]="canvasLayout()"
275
285
  >
276
286
  <ng-container #outlet />
277
287
  @if (activeOverlay()) {
@@ -285,11 +295,11 @@ export class PrismRendererComponent {
285
295
  }
286
296
  </div>
287
297
  </div>
288
- `, styles: ["\n :host { display: block; min-height: 0; flex: 1; }\n\n .prism-canvas-stage {\n position: relative;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 32px;\n min-height: 200px;\n height: 100%;\n background-color: var(--prism-bg-surface);\n background-image: radial-gradient(circle, var(--prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n transition: filter var(--dur-base);\n --prism-canvas-overlay-top: 12px;\n --prism-canvas-overlay-inline: 20px;\n }\n .prism-canvas-stage[data-rulers] {\n --prism-canvas-overlay-top: 28px;\n --prism-canvas-overlay-inline: 28px;\n }\n\n .prism-canvas-stage[data-bg=\"plain\"] {\n background-image: none;\n }\n .prism-canvas-stage[data-bg=\"light\"] {\n background-color: var(--prism-void-light, #f7f5fc);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary-from) 15%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"dark\"] {\n background-color: var(--prism-void-dark, #07050f);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary) 18%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"checker\"] {\n background-image:\n linear-gradient(45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n\n .stage-crosshair {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--dur-base);\n }\n .stage-crosshair.visible { opacity: 1; }\n .stage-crosshair::before,\n .stage-crosshair::after {\n content: '';\n position: absolute;\n background: color-mix(in srgb, var(--prism-primary) 20%, transparent);\n }\n .stage-crosshair::before { left: 0; right: 0; top: 50%; height: 1px; }\n .stage-crosshair::after { top: 0; bottom: 0; left: 50%; width: 1px; }\n\n .canvas-badges {\n position: absolute;\n top: var(--prism-canvas-overlay-top);\n left: var(--prism-canvas-overlay-inline);\n display: flex;\n gap: 6px;\n pointer-events: none;\n transition: top var(--dur-base), left var(--dur-base);\n }\n .c-badge {\n font-family: var(--font-mono);\n font-size: var(--fs-xs);\n padding: 3px 7px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--prism-bg-elevated) 90%, transparent);\n border: 1px solid var(--prism-border);\n color: var(--prism-text-muted);\n backdrop-filter: blur(8px);\n }\n\n .demo-wrap {\n position: relative;\n display: block;\n width: 100%;\n max-width: 800px;\n text-align: center;\n transform: scale(var(--zoom, 1));\n transition: transform 0.18s;\n }\n\n "] }]
298
+ `, styles: ["\n :host { display: block; min-height: 0; flex: 1; }\n\n .prism-canvas-stage {\n position: relative;\n overflow: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 32px;\n min-height: 200px;\n height: 100%;\n background-color: var(--prism-bg-surface);\n background-image: radial-gradient(circle, var(--prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n transition: filter var(--dur-base);\n --prism-canvas-overlay-top: 12px;\n --prism-canvas-overlay-inline: 20px;\n }\n .prism-canvas-stage[data-rulers] {\n --prism-canvas-overlay-top: 28px;\n --prism-canvas-overlay-inline: 28px;\n }\n\n .prism-canvas-stage[data-bg=\"plain\"] {\n background-image: none;\n }\n .prism-canvas-stage[data-bg=\"light\"] {\n background-color: var(--prism-void-light, #f7f5fc);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary-from) 15%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"dark\"] {\n background-color: var(--prism-void-dark, #07050f);\n background-image: radial-gradient(circle, color-mix(in srgb, var(--prism-primary) 18%, transparent) 1px, transparent 1px);\n }\n .prism-canvas-stage[data-bg=\"checker\"] {\n background-image:\n linear-gradient(45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n\n .stage-crosshair {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--dur-base);\n }\n .stage-crosshair.visible { opacity: 1; }\n .stage-crosshair::before,\n .stage-crosshair::after {\n content: '';\n position: absolute;\n background: color-mix(in srgb, var(--prism-primary) 20%, transparent);\n }\n .stage-crosshair::before { left: 0; right: 0; top: 50%; height: 1px; }\n .stage-crosshair::after { top: 0; bottom: 0; left: 50%; width: 1px; }\n\n .canvas-badges {\n position: absolute;\n top: var(--prism-canvas-overlay-top);\n left: var(--prism-canvas-overlay-inline);\n display: flex;\n gap: 6px;\n pointer-events: none;\n transition: top var(--dur-base), left var(--dur-base);\n }\n .c-badge {\n font-family: var(--font-mono);\n font-size: var(--fs-xs);\n padding: 3px 7px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--prism-bg-elevated) 90%, transparent);\n border: 1px solid var(--prism-border);\n color: var(--prism-text-muted);\n backdrop-filter: blur(8px);\n }\n\n .demo-wrap {\n position: relative;\n display: inline-block;\n transform: scale(var(--zoom, 1));\n transition: transform 0.18s;\n }\n .demo-wrap[data-canvas-layout=\"stretch\"] {\n display: block;\n width: 100%;\n max-width: 800px;\n }\n\n "] }]
289
299
  }], () => [], { outlet: [{ type: i0.ViewChild, args: ['outlet', { ...{
290
300
  read: ViewContainerRef,
291
301
  }, isSignal: true }] }] }); })();
292
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PrismRendererComponent, { className: "PrismRendererComponent", filePath: "app/renderer/prism-renderer.component.ts", lineNumber: 176 }); })();
302
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PrismRendererComponent, { className: "PrismRendererComponent", filePath: "app/renderer/prism-renderer.component.ts", lineNumber: 179 }); })();
293
303
  function parseContentToNodes(content) {
294
304
  if (typeof content === 'string') {
295
305
  return [htmlToNodes(content)];
@@ -1 +1 @@
1
- {"version":3,"file":"component.scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/component.scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA6BrE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EACpB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,gBAAgB,EAAE,CA8CpB"}
1
+ {"version":3,"file":"component.scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/component.scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAwCrE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EACpB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,gBAAgB,EAAE,CA8CpB"}
@@ -1,5 +1,6 @@
1
1
  import ts from 'typescript';
2
2
  import { CANVAS_BGS } from '../../shared/canvas-bg.type.js';
3
+ import { CANVAS_LAYOUTS, } from '../../shared/canvas-layout.type.js';
3
4
  const COMPONENT_STATUSES = ['stable', 'beta', 'wip', 'deprecated'];
4
5
  function isComponentStatus(value) {
5
6
  return (typeof value === 'string' &&
@@ -11,6 +12,10 @@ function isCanvasBg(value) {
11
12
  return (typeof value === 'string' &&
12
13
  CANVAS_BGS.includes(value));
13
14
  }
15
+ function isCanvasLayout(value) {
16
+ return (typeof value === 'string' &&
17
+ CANVAS_LAYOUTS.includes(value));
18
+ }
14
19
  /**
15
20
  * Scan exported symbols for Angular components annotated with @Showcase.
16
21
  */
@@ -107,6 +112,15 @@ function extractShowcaseConfig(decorator, className) {
107
112
  `expected one of: dots, plain, light, dark, checker. Skipping.`);
108
113
  }
109
114
  }
115
+ if (obj['canvasLayout'] !== undefined) {
116
+ if (isCanvasLayout(obj['canvasLayout'])) {
117
+ config.canvasLayout = obj['canvasLayout'];
118
+ }
119
+ else {
120
+ console.warn(`⚠ ng-prism: ${className} declares invalid canvasLayout "${String(obj['canvasLayout'])}" — ` +
121
+ `expected one of: ${CANVAS_LAYOUTS.join(', ')}. Skipping.`);
122
+ }
123
+ }
110
124
  if (Array.isArray(obj['variants'])) {
111
125
  config.variants = obj['variants'].map((variant) => {
112
126
  const cleaned = { ...variant };
@@ -115,6 +129,12 @@ function extractShowcaseConfig(decorator, className) {
115
129
  `invalid bg "${String(variant['bg'])}" — expected one of: dots, plain, light, dark, checker. Skipping.`);
116
130
  delete cleaned['bg'];
117
131
  }
132
+ if (variant['canvasLayout'] !== undefined &&
133
+ !isCanvasLayout(variant['canvasLayout'])) {
134
+ console.warn(`⚠ ng-prism: ${className} variant "${String(variant['name'])}" declares ` +
135
+ `invalid canvasLayout "${String(variant['canvasLayout'])}" — expected one of: ${CANVAS_LAYOUTS.join(', ')}. Skipping.`);
136
+ delete cleaned['canvasLayout'];
137
+ }
118
138
  return cleaned;
119
139
  });
120
140
  }
@@ -5,7 +5,7 @@ export interface PrismPipelineOptions {
5
5
  libraryImportPath: string;
6
6
  prismProject: string;
7
7
  configFile: string;
8
- /** Absolute path. If omitted, defaults to `<workspaceRoot>/.ng-prism/<prismProject>`. */
8
+ /** Absolute path. If omitted, defaults to `<workspaceRoot>/ng-prism-cache/<prismProject>`. */
9
9
  cacheDir?: string;
10
10
  }
11
11
  export interface PrismPipelineResult {
@@ -1 +1 @@
1
- {"version":3,"file":"prism-pipeline.d.ts","sourceRoot":"","sources":["../../../src/builder/shared/prism-pipeline.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAYpE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,oGAAoG;IACpG,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAExD;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAyE9B"}
1
+ {"version":3,"file":"prism-pipeline.d.ts","sourceRoot":"","sources":["../../../src/builder/shared/prism-pipeline.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAYpE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,oGAAoG;IACpG,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAExD;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAyE9B"}
@@ -1,5 +1,5 @@
1
1
  import { join, dirname } from 'path';
2
- import { writeFileSync, readFileSync, mkdirSync, statSync, renameSync, existsSync, unlinkSync, } from 'fs';
2
+ import { writeFileSync, readFileSync, mkdirSync, statSync, existsSync, } from 'fs';
3
3
  import ts from 'typescript';
4
4
  import { createScanner } from '../scanner/scanner.js';
5
5
  import { discoverSecondaryEntryPoints } from '../scanner/entry-point-discovery.js';
@@ -45,7 +45,8 @@ export async function runPrismPipeline(options, context, state) {
45
45
  pages: manifest.pages,
46
46
  meta: manifest.meta,
47
47
  });
48
- const cacheDir = options.cacheDir ?? join(workspaceRoot, '.ng-prism', options.prismProject);
48
+ const cacheRoot = options.cacheDir ?? join(workspaceRoot, 'ng-prism-cache');
49
+ const cacheDir = join(cacheRoot, options.prismProject);
49
50
  const manifestPath = join(cacheDir, 'prism-manifest.ts');
50
51
  mkdirSync(cacheDir, { recursive: true });
51
52
  const written = writeManifestIfChanged(manifestPath, source);
@@ -69,22 +70,17 @@ function writeManifestIfChanged(manifestPath, newContent) {
69
70
  return false;
70
71
  }
71
72
  }
72
- const tempPath = manifestPath + '.tmp';
73
- writeFileSync(tempPath, newContent, 'utf-8');
74
- try {
75
- renameSync(tempPath, manifestPath);
76
- }
77
- catch (err) {
78
- if (existsSync(tempPath)) {
79
- try {
80
- unlinkSync(tempPath);
81
- }
82
- catch {
83
- /* best-effort cleanup */
84
- }
85
- }
86
- throw err;
87
- }
73
+ // In-place write (truncate + write to the existing inode). The previous
74
+ // implementation used a temp file + atomic rename, which produces a fresh
75
+ // inode on every write. That breaks file watchers — most importantly Vite's
76
+ // — when the manifest lives in a cache dir outside the prism project's
77
+ // source root: Vite watches the file by path/inode, loses the handle on
78
+ // rename, and never picks up subsequent rewrites. The result for the user
79
+ // is that @Showcase changes never trigger an HMR / reload. The window
80
+ // between truncate and write is small (single syscall for kilobyte-sized
81
+ // manifests), so the risk of a bundler observing a partial file is
82
+ // negligible in practice.
83
+ writeFileSync(manifestPath, newContent, 'utf-8');
88
84
  return true;
89
85
  }
90
86
  function isDirectory(path) {
@@ -1,5 +1,6 @@
1
1
  import type { InputSignalWithTransform, Provider } from '@angular/core';
2
2
  import type { CanvasBg } from '../shared/canvas-bg.type.js';
3
+ import type { CanvasLayout } from '../shared/canvas-layout.type.js';
3
4
  export type ComponentStatus = 'stable' | 'beta' | 'wip' | 'deprecated';
4
5
  export interface DirectiveHost {
5
6
  selector: string;
@@ -52,6 +53,15 @@ export interface ShowcaseConfig<T = unknown> {
52
53
  * resets when switching variants or components.
53
54
  */
54
55
  bg?: CanvasBg;
56
+ /**
57
+ * Canvas layout mode for the rendered component.
58
+ * - `'fit'` (default): wrapper shrinks to content, component is centered in the canvas.
59
+ * - `'stretch'`: wrapper takes full canvas width (up to a sensible max) so block-level
60
+ * components without intrinsic width (e.g. horizontal dividers) and components that
61
+ * opt into `width: 100%` (e.g. full-width buttons) render correctly.
62
+ * A `Variant.canvasLayout` overrides this.
63
+ */
64
+ canvasLayout?: CanvasLayout;
55
65
  /** Host element for directive showcases. String = HTML element (e.g. '<button class="btn">'), object = Angular component. */
56
66
  host?: string | DirectiveHost;
57
67
  /** Title of a registered ComponentPage to render instead of the component itself. Use for complex components that need template projections or mock data. The page component can inject PrismRendererService to react to control panel changes. */
@@ -81,6 +91,8 @@ export interface Variant<T = unknown> {
81
91
  meta?: Record<string, unknown>;
82
92
  /** Recommended canvas background for this variant. Overrides `ShowcaseConfig.bg`. */
83
93
  bg?: CanvasBg;
94
+ /** Canvas layout mode for this variant. Overrides `ShowcaseConfig.canvasLayout`. See `ShowcaseConfig.canvasLayout` for semantics. */
95
+ canvasLayout?: CanvasLayout;
84
96
  }
85
97
  export {};
86
98
  //# sourceMappingURL=showcase.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"showcase.types.d.ts","sourceRoot":"","sources":["../../src/decorator/showcase.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAOD,KAAK,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,wBAAwB,CAC5D,GAAG,EACH,MAAM,MAAM,CACb,GACG,MAAM,GACN,KAAK,CAAC;AAEV;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAC3C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB;KACG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,GAC5D,CAAC,GACD,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEN,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2IAA2I;IAC3I,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iJAAiJ;IACjJ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACxB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,6HAA6H;IAC7H,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IAC9B,mPAAmP;IACnP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IAClC,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,0IAA0I;IAC1I,MAAM,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,qFAAqF;IACrF,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf"}
1
+ {"version":3,"file":"showcase.types.d.ts","sourceRoot":"","sources":["../../src/decorator/showcase.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAOD,KAAK,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,wBAAwB,CAC5D,GAAG,EACH,MAAM,MAAM,CACb,GACG,MAAM,GACN,KAAK,CAAC;AAEV;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAC3C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB;KACG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,GAC5D,CAAC,GACD,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEN,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2IAA2I;IAC3I,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iJAAiJ;IACjJ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACxB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,6HAA6H;IAC7H,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IAC9B,mPAAmP;IACnP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IAClC,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,0IAA0I;IAC1I,MAAM,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,qFAAqF;IACrF,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,qIAAqI;IACrI,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/schematics/migrations/v21-13-manifest-cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,4BAA4B,CAAC;AAsK/E,wBAAgB,OAAO,IAAI,IAAI,CAiB9B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/schematics/migrations/v21-13-manifest-cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,4BAA4B,CAAC;AAiM/E,wBAAgB,OAAO,IAAI,IAAI,CAiB9B"}
@@ -1,8 +1,18 @@
1
1
  import { addTsConfigPath } from '../../utils/tsconfig-paths.js';
2
2
  const OLD_IMPORT = /^import\s+\{\s*PRISM_RUNTIME_MANIFEST\s*\}\s+from\s+['"](?:\.\/prism-manifest|prism-manifest)['"]\s*;?$/m;
3
+ /**
4
+ * Matches a Vite HMR accept call whose dependency target is the legacy
5
+ * `./prism-manifest` module specifier. Captures everything after the dep
6
+ * argument so the rewrite preserves the original callback and trailing
7
+ * code verbatim.
8
+ */
9
+ const OLD_HMR_ACCEPT = /\.accept\s*\(\s*(['"])\.\/prism-manifest\1\s*(,)/g;
3
10
  function buildNewImport(prismProject) {
4
11
  return `import { PRISM_RUNTIME_MANIFEST } from 'prism-manifest/${prismProject}';`;
5
12
  }
13
+ function buildNewHmrAcceptTarget(prismProject) {
14
+ return `.accept('prism-manifest/${prismProject}',`;
15
+ }
6
16
  function readWorkspace(tree) {
7
17
  const buffer = tree.read('angular.json');
8
18
  if (!buffer)
@@ -34,24 +44,36 @@ function rewriteMainTs(tree, context, workspace, prismProject) {
34
44
  if (!buffer)
35
45
  return;
36
46
  const newImport = buildNewImport(prismProject);
47
+ const newHmrTarget = buildNewHmrAcceptTarget(prismProject);
37
48
  const content = buffer.toString('utf-8');
38
- if (content.includes(newImport))
49
+ const importMatches = OLD_IMPORT.test(content);
50
+ const hmrMatches = OLD_HMR_ACCEPT.test(content);
51
+ OLD_HMR_ACCEPT.lastIndex = 0;
52
+ if (content.includes(newImport) && !hmrMatches)
39
53
  return;
40
- if (!OLD_IMPORT.test(content)) {
54
+ let next = content;
55
+ if (importMatches) {
56
+ next = next.replace(OLD_IMPORT, newImport);
57
+ }
58
+ else if (!next.includes(newImport)) {
41
59
  context.logger.warn(`ng-prism migration: could not find PRISM_RUNTIME_MANIFEST import in ${mainPath}. ` +
42
60
  `Update it manually to: ${newImport}`);
43
- return;
44
61
  }
45
- tree.overwrite(mainPath, content.replace(OLD_IMPORT, newImport));
62
+ if (hmrMatches) {
63
+ next = next.replace(OLD_HMR_ACCEPT, newHmrTarget);
64
+ }
65
+ if (next !== content) {
66
+ tree.overwrite(mainPath, next);
67
+ }
46
68
  }
47
69
  function addTsConfigMapping(tree) {
48
70
  addTsConfigPath(tree, 'tsconfig.json', 'prism-manifest/*', [
49
- './.ng-prism/*/prism-manifest.ts',
71
+ './ng-prism-cache/*/prism-manifest.ts',
50
72
  ]);
51
73
  }
52
74
  function ensureNgPrismGitignoreEntry(tree) {
53
75
  const path = '.gitignore';
54
- const entry = '.ng-prism/';
76
+ const entry = 'ng-prism-cache/';
55
77
  const buffer = tree.read(path);
56
78
  if (!buffer) {
57
79
  tree.create(path, entry + '\n');
@@ -88,7 +110,7 @@ function addCacheIncludeToTsconfigApp(tree, workspace, prismProject) {
88
110
  const include = Array.isArray(parsed.include)
89
111
  ? parsed.include
90
112
  : [];
91
- const includeEntry = `../../.ng-prism/${prismProject}/**/*.ts`;
113
+ const includeEntry = `../../ng-prism-cache/${prismProject}/**/*.ts`;
92
114
  const includeChanged = !include.includes(includeEntry);
93
115
  const nextInclude = includeChanged ? [...include, includeEntry] : include;
94
116
  const compilerOptions = { ...(parsed.compilerOptions ?? {}) };
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '@angular-devkit/schematics';
2
+ export declare function migrate(): Rule;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/schematics/migrations/v22-0-cache-dir-rename/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA0B,MAAM,4BAA4B,CAAC;AAmJ/E,wBAAgB,OAAO,IAAI,IAAI,CAsB9B"}
@@ -0,0 +1,138 @@
1
+ import { addTsConfigPath } from '../../utils/tsconfig-paths.js';
2
+ const OLD_DIR = '.ng-prism';
3
+ const NEW_DIR = 'ng-prism-cache';
4
+ const OLD_GITIGNORE_ENTRY = '.ng-prism/';
5
+ const NEW_GITIGNORE_ENTRY = 'ng-prism-cache/';
6
+ const OLD_PATH_MAPPING = './.ng-prism/*/prism-manifest.ts';
7
+ const NEW_PATH_MAPPING = './ng-prism-cache/*/prism-manifest.ts';
8
+ function readWorkspace(tree) {
9
+ const buffer = tree.read('angular.json');
10
+ if (!buffer)
11
+ return undefined;
12
+ return JSON.parse(buffer.toString('utf-8'));
13
+ }
14
+ function findPrismProjects(workspace) {
15
+ const projects = workspace.projects ?? {};
16
+ const result = [];
17
+ for (const [, project] of Object.entries(projects)) {
18
+ const architect = project.architect ?? {};
19
+ for (const target of Object.values(architect)) {
20
+ if (target.builder === '@ng-prism/core:serve') {
21
+ const prismProject = target.options?.['prismProject'];
22
+ if (typeof prismProject === 'string' &&
23
+ !result.includes(prismProject)) {
24
+ result.push(prismProject);
25
+ }
26
+ }
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ /**
32
+ * Replace the `prism-manifest/*` path mapping if it still points at the old
33
+ * `.ng-prism/` location, while preserving any user customisation that already
34
+ * uses a different target.
35
+ */
36
+ function updateTsConfigMapping(tree, context) {
37
+ const buffer = tree.read('tsconfig.json');
38
+ if (!buffer)
39
+ return;
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(buffer.toString('utf-8'));
43
+ }
44
+ catch {
45
+ context.logger.warn('ng-prism migration: tsconfig.json could not be parsed; skipping path-mapping update. Update "prism-manifest/*" to ' +
46
+ `["${NEW_PATH_MAPPING}"] manually.`);
47
+ return;
48
+ }
49
+ const existing = parsed.compilerOptions?.paths?.['prism-manifest/*'];
50
+ if (!existing) {
51
+ // No existing mapping — fall through to addTsConfigPath which inserts the new default.
52
+ addTsConfigPath(tree, 'tsconfig.json', 'prism-manifest/*', [
53
+ NEW_PATH_MAPPING,
54
+ ]);
55
+ return;
56
+ }
57
+ // Replace any entries that still reference the legacy dot-dir; leave the rest alone.
58
+ const updated = existing.map((entry) => entry === OLD_PATH_MAPPING ? NEW_PATH_MAPPING : entry);
59
+ if (updated.every((entry, i) => entry === existing[i]))
60
+ return;
61
+ parsed.compilerOptions.paths['prism-manifest/*'] = updated;
62
+ tree.overwrite('tsconfig.json', JSON.stringify(parsed, null, 2) + '\n');
63
+ }
64
+ function updateTsConfigAppInclude(tree, workspace, prismProject) {
65
+ const project = workspace.projects?.[prismProject];
66
+ const projectRoot = project?.root ?? `projects/${prismProject}`;
67
+ const path = `${projectRoot}/tsconfig.app.json`;
68
+ const buffer = tree.read(path);
69
+ if (!buffer)
70
+ return;
71
+ const sourceText = buffer.toString('utf-8');
72
+ let parsed;
73
+ try {
74
+ parsed = JSON.parse(sourceText);
75
+ }
76
+ catch {
77
+ return;
78
+ }
79
+ if (!Array.isArray(parsed.include))
80
+ return;
81
+ const oldEntry = `../../${OLD_DIR}/${prismProject}/**/*.ts`;
82
+ const newEntry = `../../${NEW_DIR}/${prismProject}/**/*.ts`;
83
+ const include = parsed.include;
84
+ const oldIndex = include.indexOf(oldEntry);
85
+ if (oldIndex === -1 && include.includes(newEntry))
86
+ return;
87
+ if (oldIndex === -1)
88
+ return;
89
+ const next = [...include];
90
+ next[oldIndex] = newEntry;
91
+ // Avoid duplicates if user already had both entries for some reason.
92
+ const deduped = Array.from(new Set(next));
93
+ const updated = { ...parsed, include: deduped };
94
+ tree.overwrite(path, JSON.stringify(updated, null, 2) + '\n');
95
+ }
96
+ function renameGitignoreEntry(tree) {
97
+ const path = '.gitignore';
98
+ const buffer = tree.read(path);
99
+ if (!buffer)
100
+ return;
101
+ const content = buffer.toString('utf-8');
102
+ const lines = content.split('\n');
103
+ let changed = false;
104
+ const next = lines.map((line) => {
105
+ if (line.trim() === OLD_GITIGNORE_ENTRY) {
106
+ changed = true;
107
+ return line.replace(OLD_GITIGNORE_ENTRY, NEW_GITIGNORE_ENTRY);
108
+ }
109
+ return line;
110
+ });
111
+ if (!changed) {
112
+ // Ensure the new entry exists even if the old one was already missing.
113
+ if (next.some((line) => line.trim() === NEW_GITIGNORE_ENTRY))
114
+ return;
115
+ tree.overwrite(path, content.trimEnd() + '\n' + NEW_GITIGNORE_ENTRY + '\n');
116
+ return;
117
+ }
118
+ tree.overwrite(path, next.join('\n'));
119
+ }
120
+ export function migrate() {
121
+ return (tree, context) => {
122
+ const workspace = readWorkspace(tree);
123
+ if (!workspace)
124
+ return tree;
125
+ const prismProjects = findPrismProjects(workspace);
126
+ if (prismProjects.length === 0)
127
+ return tree;
128
+ updateTsConfigMapping(tree, context);
129
+ for (const prismProject of prismProjects) {
130
+ updateTsConfigAppInclude(tree, workspace, prismProject);
131
+ }
132
+ renameGitignoreEntry(tree);
133
+ context.logger.info('ng-prism migration: cache directory renamed from .ng-prism/ to ng-prism-cache/. ' +
134
+ 'You can safely delete the old .ng-prism/ directory from your workspace — ' +
135
+ 'the builder will regenerate the manifest on next serve/build run.');
136
+ return tree;
137
+ };
138
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,IAAI,EAIV,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAqWtD,wBAAgB,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAWvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/schematics/ng-add/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,IAAI,EAIV,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAkXtD,wBAAgB,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAWvD"}
@@ -22,31 +22,43 @@ function addPrismAppProject(options) {
22
22
  const prismRoot = `projects/${prismProjectName}`;
23
23
  const prismSrc = `${prismRoot}/src`;
24
24
  const zoneless = options.zoneless === true;
25
+ const hotConst = "const hot = (import.meta as ImportMeta & { hot?: { accept(dep: string, cb: (mod: { PRISM_RUNTIME_MANIFEST: typeof PRISM_RUNTIME_MANIFEST } | undefined) => void): void } }).hot;";
26
+ const hmrThen = [
27
+ '.then((appRef) => {',
28
+ ` hot?.accept('prism-manifest/${prismProjectName}', (mod) => {`,
29
+ ' if (mod) enablePrismHmr(appRef, mod.PRISM_RUNTIME_MANIFEST);',
30
+ ' });',
31
+ '});',
32
+ ].join('\n');
25
33
  const mainTs = zoneless
26
34
  ? [
27
35
  "import { provideZonelessChangeDetection } from '@angular/core';",
28
36
  "import { bootstrapApplication } from '@angular/platform-browser';",
29
- "import { PrismShellComponent, providePrism } from '@ng-prism/core';",
37
+ "import { enablePrismHmr, PrismShellComponent, providePrism } from '@ng-prism/core';",
30
38
  `import { PRISM_RUNTIME_MANIFEST } from 'prism-manifest/${prismProjectName}';`,
31
39
  "import config from 'ng-prism.config';",
32
40
  '',
41
+ hotConst,
42
+ '',
33
43
  'bootstrapApplication(PrismShellComponent, {',
34
44
  ' providers: [',
35
45
  ' provideZonelessChangeDetection(),',
36
46
  ' providePrism(PRISM_RUNTIME_MANIFEST, config),',
37
47
  ' ],',
38
- '});',
48
+ '})' + hmrThen,
39
49
  '',
40
50
  ].join('\n')
41
51
  : [
42
52
  "import { bootstrapApplication } from '@angular/platform-browser';",
43
- "import { PrismShellComponent, providePrism } from '@ng-prism/core';",
53
+ "import { enablePrismHmr, PrismShellComponent, providePrism } from '@ng-prism/core';",
44
54
  `import { PRISM_RUNTIME_MANIFEST } from 'prism-manifest/${prismProjectName}';`,
45
55
  "import config from 'ng-prism.config';",
46
56
  '',
57
+ hotConst,
58
+ '',
47
59
  'bootstrapApplication(PrismShellComponent, {',
48
60
  ' providers: [providePrism(PRISM_RUNTIME_MANIFEST, config)],',
49
- '});',
61
+ '})' + hmrThen,
50
62
  '',
51
63
  ].join('\n');
52
64
  if (!tree.exists(`${prismSrc}/main.ts`)) {
@@ -83,7 +95,7 @@ function addPrismAppProject(options) {
83
95
  files: ['src/main.ts'],
84
96
  include: [
85
97
  'src/**/*.d.ts',
86
- `../../.ng-prism/${prismProjectName}/**/*.ts`,
98
+ `../../ng-prism-cache/${prismProjectName}/**/*.ts`,
87
99
  ],
88
100
  };
89
101
  tree.create(tsconfigAppPath, JSON.stringify(tsconfigApp, null, 2) + '\n');
@@ -196,7 +208,7 @@ function addTsConfigPaths(options) {
196
208
  `./${sourceRoot}/public-api.ts`,
197
209
  ]);
198
210
  addTsConfigPath(tree, tsConfigPath, 'prism-manifest/*', [
199
- './.ng-prism/*/prism-manifest.ts',
211
+ './ng-prism-cache/*/prism-manifest.ts',
200
212
  ]);
201
213
  return tree;
202
214
  };
@@ -260,7 +272,7 @@ function logSetupSummary(options) {
260
272
  }
261
273
  function addNgPrismGitignoreEntry() {
262
274
  return (tree) => {
263
- const entry = '.ng-prism/';
275
+ const entry = 'ng-prism-cache/';
264
276
  const gitignorePath = '.gitignore';
265
277
  const buffer = tree.read(gitignorePath);
266
278
  if (buffer) {
@@ -0,0 +1,3 @@
1
+ export type CanvasLayout = 'fit' | 'stretch';
2
+ export declare const CANVAS_LAYOUTS: readonly CanvasLayout[];
3
+ //# sourceMappingURL=canvas-layout.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-layout.type.d.ts","sourceRoot":"","sources":["../../src/shared/canvas-layout.type.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,SAAS,CAAC;AAE7C,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAAgC,CAAC"}
@@ -0,0 +1 @@
1
+ export const CANVAS_LAYOUTS = ['fit', 'stretch'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-prism/core",
3
- "version": "22.0.0-beta.2",
3
+ "version": "22.0.0-beta.4",
4
4
  "description": "ng-prism — the Angular-native Storybook alternative. Lightweight component showcase with @Showcase decorator, no story files needed.",
5
5
  "keywords": [
6
6
  "ng-prism",
@@ -3,8 +3,13 @@
3
3
  "schematics": {
4
4
  "migration-v22-manifest-cache": {
5
5
  "version": "22.0.0-beta.0",
6
- "description": "Move generated prism-manifest.ts into <workspaceRoot>/.ng-prism/<prismProject>/ and resolve it via a wildcard tsconfig path mapping.",
6
+ "description": "Move generated prism-manifest.ts into <workspaceRoot>/ng-prism-cache/<prismProject>/ and resolve it via a wildcard tsconfig path mapping.",
7
7
  "factory": "../dist/schematics/migrations/v21-13-manifest-cache/index#migrate"
8
+ },
9
+ "migration-v22-cache-dir-rename": {
10
+ "version": "22.0.0-beta.4",
11
+ "description": "Rename the manifest cache directory from .ng-prism/ to ng-prism-cache/. The dot-prefixed name was silently excluded from @angular/build's watcher (hardcoded **/.*/** ignore pattern), so @Showcase decorator edits never triggered an HMR / reload.",
12
+ "factory": "../dist/schematics/migrations/v22-0-cache-dir-rename/index#migrate"
8
13
  }
9
14
  }
10
15
  }