codexly-ui 0.10.98 → 0.10.100

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.
@@ -2148,9 +2148,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
2148
2148
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }] } });
2149
2149
 
2150
2150
  const STEPPER_SIZE_MAP = {
2151
- sm: { circle: 'w-7 h-7', iconSize: 'xs', label: 'text-xs', desc: 'text-xs', connector: 'h-0.5' },
2152
- md: { circle: 'w-9 h-9', iconSize: 'sm', label: 'text-sm', desc: 'text-xs', connector: 'h-0.5' },
2153
- lg: { circle: 'w-11 h-11', iconSize: 'md', label: 'text-sm', desc: 'text-xs', connector: 'h-1' },
2151
+ sm: { circle: 'w-7 h-7', iconSize: 'xs', label: 'text-xs', desc: 'text-xs', connector: 'h-0.5', connectorOffsetH: 'mt-3.5' },
2152
+ md: { circle: 'w-9 h-9', iconSize: 'sm', label: 'text-sm', desc: 'text-xs', connector: 'h-0.5', connectorOffsetH: 'mt-4.5' },
2153
+ lg: { circle: 'w-11 h-11', iconSize: 'md', label: 'text-sm', desc: 'text-xs', connector: 'h-1', connectorOffsetH: 'mt-[1.375rem]' },
2154
2154
  };
2155
2155
 
2156
2156
  class ClxStepperComponent {
@@ -2169,24 +2169,25 @@ class ClxStepperComponent {
2169
2169
  : 'flex flex-col w-full';
2170
2170
  }, ...(ngDevMode ? [{ debugName: "_hostClass" }] : /* istanbul ignore next */ []));
2171
2171
  // ── Step wrapper ──────────────────────────────────────────────────────────────
2172
+ // Horizontal: circle-column first (fixed to its own content width), connector fills the
2173
+ // rest of the step's flex-1 share — so the label (inside the circle column) always centers
2174
+ // under its own circle instead of under circle+connector combined.
2172
2175
  _stepWrapClass = computed(() => {
2173
2176
  const horiz = this.orientation() === 'horizontal';
2174
2177
  return horiz
2175
- ? 'flex flex-col items-center flex-1 min-w-0'
2176
- : 'flex flex-row gap-3';
2178
+ ? 'flex flex-row items-start flex-1 min-w-0'
2179
+ : 'flex flex-row';
2177
2180
  }, ...(ngDevMode ? [{ debugName: "_stepWrapClass" }] : /* istanbul ignore next */ []));
2178
- // ── Axis (circle + connector) ─────────────────────────────────────────────────
2179
- _axisClass = computed(() => {
2180
- const horiz = this.orientation() === 'horizontal';
2181
- return horiz
2182
- ? 'flex flex-row items-center w-full'
2183
- : 'flex flex-col items-center shrink-0';
2184
- }, ...(ngDevMode ? [{ debugName: "_axisClass" }] : /* istanbul ignore next */ []));
2181
+ // ── Circle column ──────────────────────────────────────────────────────────────
2182
+ // Horizontal: circle + label stacked, so the label centers directly under the circle
2183
+ // regardless of the connector's flex-1 width next to it.
2184
+ // Vertical: circle + connector stacked, with the label as a separate sibling beside it.
2185
+ _circleColClass = computed(() => 'flex flex-col items-center shrink-0', ...(ngDevMode ? [{ debugName: "_circleColClass" }] : /* istanbul ignore next */ []));
2185
2186
  // ── Label wrapper ─────────────────────────────────────────────────────────────
2186
2187
  _labelWrapClass = computed(() => {
2187
2188
  const horiz = this.orientation() === 'horizontal';
2188
2189
  return horiz
2189
- ? 'flex flex-col items-center text-center mt-2 px-1'
2190
+ ? 'flex flex-col items-center text-center mt-2 px-1 max-w-[8rem]'
2190
2191
  : 'flex flex-col justify-center pb-6 min-w-0';
2191
2192
  }, ...(ngDevMode ? [{ debugName: "_labelWrapClass" }] : /* istanbul ignore next */ []));
2192
2193
  // ── Circle ────────────────────────────────────────────────────────────────────
@@ -2205,10 +2206,10 @@ class ClxStepperComponent {
2205
2206
  _connectorClass(status) {
2206
2207
  const t = resolveColor(this._color());
2207
2208
  const horiz = this.orientation() === 'horizontal';
2208
- const size = this._tokens().connector;
2209
+ const tokens = this._tokens();
2209
2210
  const filled = status === 'completed' ? `${t.bg}` : 'bg-clx-border';
2210
2211
  return horiz
2211
- ? `flex-1 ${size} ${filled} transition-colors duration-300`
2212
+ ? `flex-1 ${tokens.connector} ${tokens.connectorOffsetH} ${filled} transition-colors duration-300`
2212
2213
  : `w-0.5 flex-1 my-1 min-h-[1.5rem] ${filled} transition-colors duration-300`;
2213
2214
  }
2214
2215
  // ── Label ─────────────────────────────────────────────────────────────────────
@@ -2227,104 +2228,134 @@ class ClxStepperComponent {
2227
2228
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxStepperComponent, isStandalone: true, selector: "clx-stepper", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "_hostClass()" } }, ngImport: i0, template: `
2228
2229
  @for (step of steps(); track $index; let last = $last; let i = $index) {
2229
2230
 
2230
- <!-- Step -->
2231
+ <!-- Horizontal: circle+label form one fixed-width column, connector is a separate flex-1
2232
+ track next to it — so the label centers under its own circle, not under circle+connector.
2233
+ Vertical: circle+connector form one column, label sits beside it. -->
2231
2234
  <div [class]="_stepWrapClass()">
2232
2235
 
2233
- <!-- Circle + connector (horizontal: connector after, vertical: connector below) -->
2234
- <div [class]="_axisClass()">
2235
-
2236
- <!-- Circle -->
2237
- <div [class]="_circleClass(step.status)">
2238
- @switch (step.status) {
2239
- @case ('completed') {
2240
- <span clx-icon name="check" [size]="_tokens().iconSize"></span>
2241
- }
2242
- @case ('error') {
2243
- <span clx-icon name="close" [size]="_tokens().iconSize"></span>
2244
- }
2245
- @default {
2246
- @if (step.icon) {
2247
- <span clx-icon [name]="step.icon" [size]="_tokens().iconSize"></span>
2248
- } @else {
2249
- <span [class]="'font-bold leading-none select-none ' + _tokens().label">{{ i + 1 }}</span>
2250
- }
2236
+ @if (orientation() === 'horizontal') {
2237
+ <div [class]="_circleColClass()">
2238
+ <div [class]="_circleClass(step.status)">
2239
+ <ng-container [ngTemplateOutlet]="circleContent" [ngTemplateOutletContext]="{ step, i }" />
2240
+ </div>
2241
+ <div [class]="_labelWrapClass()">
2242
+ <span [class]="_labelClass(step.status)">{{ step.label }}</span>
2243
+ @if (step.description) {
2244
+ <span [class]="'text-clx-text-subtle ' + _tokens().desc">{{ step.description }}</span>
2251
2245
  }
2252
- }
2246
+ </div>
2253
2247
  </div>
2254
-
2255
- <!-- Connector -->
2256
2248
  @if (!last) {
2257
2249
  <div [class]="_connectorClass(step.status)"></div>
2258
2250
  }
2259
-
2260
- </div>
2261
-
2262
- <!-- Label + description -->
2263
- <div [class]="_labelWrapClass()">
2264
- <span [class]="_labelClass(step.status)">{{ step.label }}</span>
2265
- @if (step.description) {
2266
- <span [class]="'text-clx-text-subtle ' + _tokens().desc">{{ step.description }}</span>
2267
- }
2268
- </div>
2251
+ } @else {
2252
+ <div [class]="_circleColClass()">
2253
+ <div [class]="_circleClass(step.status)">
2254
+ <ng-container [ngTemplateOutlet]="circleContent" [ngTemplateOutletContext]="{ step, i }" />
2255
+ </div>
2256
+ @if (!last) {
2257
+ <div [class]="_connectorClass(step.status)"></div>
2258
+ }
2259
+ </div>
2260
+ <div [class]="_labelWrapClass()">
2261
+ <span [class]="_labelClass(step.status)">{{ step.label }}</span>
2262
+ @if (step.description) {
2263
+ <span [class]="'text-clx-text-subtle ' + _tokens().desc">{{ step.description }}</span>
2264
+ }
2265
+ </div>
2266
+ }
2269
2267
 
2270
2268
  </div>
2271
2269
  }
2272
- `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2270
+
2271
+ <ng-template #circleContent let-step="step" let-i="i">
2272
+ @switch (step.status) {
2273
+ @case ('completed') {
2274
+ <span clx-icon name="check" [size]="_tokens().iconSize"></span>
2275
+ }
2276
+ @case ('error') {
2277
+ <span clx-icon name="close" [size]="_tokens().iconSize"></span>
2278
+ }
2279
+ @default {
2280
+ @if (step.icon) {
2281
+ <span clx-icon [name]="step.icon" [size]="_tokens().iconSize"></span>
2282
+ } @else {
2283
+ <span [class]="'font-bold leading-none select-none ' + _tokens().label">{{ i + 1 }}</span>
2284
+ }
2285
+ }
2286
+ }
2287
+ </ng-template>
2288
+ `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2273
2289
  }
2274
2290
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxStepperComponent, decorators: [{
2275
2291
  type: Component,
2276
2292
  args: [{
2277
2293
  selector: 'clx-stepper',
2278
2294
  standalone: true,
2279
- imports: [ClxIconComponent],
2295
+ imports: [ClxIconComponent, NgTemplateOutlet],
2280
2296
  encapsulation: ViewEncapsulation.None,
2281
2297
  changeDetection: ChangeDetectionStrategy.OnPush,
2282
2298
  host: { '[class]': '_hostClass()' },
2283
2299
  template: `
2284
2300
  @for (step of steps(); track $index; let last = $last; let i = $index) {
2285
2301
 
2286
- <!-- Step -->
2302
+ <!-- Horizontal: circle+label form one fixed-width column, connector is a separate flex-1
2303
+ track next to it — so the label centers under its own circle, not under circle+connector.
2304
+ Vertical: circle+connector form one column, label sits beside it. -->
2287
2305
  <div [class]="_stepWrapClass()">
2288
2306
 
2289
- <!-- Circle + connector (horizontal: connector after, vertical: connector below) -->
2290
- <div [class]="_axisClass()">
2291
-
2292
- <!-- Circle -->
2293
- <div [class]="_circleClass(step.status)">
2294
- @switch (step.status) {
2295
- @case ('completed') {
2296
- <span clx-icon name="check" [size]="_tokens().iconSize"></span>
2297
- }
2298
- @case ('error') {
2299
- <span clx-icon name="close" [size]="_tokens().iconSize"></span>
2300
- }
2301
- @default {
2302
- @if (step.icon) {
2303
- <span clx-icon [name]="step.icon" [size]="_tokens().iconSize"></span>
2304
- } @else {
2305
- <span [class]="'font-bold leading-none select-none ' + _tokens().label">{{ i + 1 }}</span>
2306
- }
2307
+ @if (orientation() === 'horizontal') {
2308
+ <div [class]="_circleColClass()">
2309
+ <div [class]="_circleClass(step.status)">
2310
+ <ng-container [ngTemplateOutlet]="circleContent" [ngTemplateOutletContext]="{ step, i }" />
2311
+ </div>
2312
+ <div [class]="_labelWrapClass()">
2313
+ <span [class]="_labelClass(step.status)">{{ step.label }}</span>
2314
+ @if (step.description) {
2315
+ <span [class]="'text-clx-text-subtle ' + _tokens().desc">{{ step.description }}</span>
2307
2316
  }
2308
- }
2317
+ </div>
2309
2318
  </div>
2310
-
2311
- <!-- Connector -->
2312
2319
  @if (!last) {
2313
2320
  <div [class]="_connectorClass(step.status)"></div>
2314
2321
  }
2315
-
2316
- </div>
2317
-
2318
- <!-- Label + description -->
2319
- <div [class]="_labelWrapClass()">
2320
- <span [class]="_labelClass(step.status)">{{ step.label }}</span>
2321
- @if (step.description) {
2322
- <span [class]="'text-clx-text-subtle ' + _tokens().desc">{{ step.description }}</span>
2323
- }
2324
- </div>
2322
+ } @else {
2323
+ <div [class]="_circleColClass()">
2324
+ <div [class]="_circleClass(step.status)">
2325
+ <ng-container [ngTemplateOutlet]="circleContent" [ngTemplateOutletContext]="{ step, i }" />
2326
+ </div>
2327
+ @if (!last) {
2328
+ <div [class]="_connectorClass(step.status)"></div>
2329
+ }
2330
+ </div>
2331
+ <div [class]="_labelWrapClass()">
2332
+ <span [class]="_labelClass(step.status)">{{ step.label }}</span>
2333
+ @if (step.description) {
2334
+ <span [class]="'text-clx-text-subtle ' + _tokens().desc">{{ step.description }}</span>
2335
+ }
2336
+ </div>
2337
+ }
2325
2338
 
2326
2339
  </div>
2327
2340
  }
2341
+
2342
+ <ng-template #circleContent let-step="step" let-i="i">
2343
+ @switch (step.status) {
2344
+ @case ('completed') {
2345
+ <span clx-icon name="check" [size]="_tokens().iconSize"></span>
2346
+ }
2347
+ @case ('error') {
2348
+ <span clx-icon name="close" [size]="_tokens().iconSize"></span>
2349
+ }
2350
+ @default {
2351
+ @if (step.icon) {
2352
+ <span clx-icon [name]="step.icon" [size]="_tokens().iconSize"></span>
2353
+ } @else {
2354
+ <span [class]="'font-bold leading-none select-none ' + _tokens().label">{{ i + 1 }}</span>
2355
+ }
2356
+ }
2357
+ }
2358
+ </ng-template>
2328
2359
  `,
2329
2360
  }]
2330
2361
  }], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
@@ -10160,17 +10191,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10160
10191
  }], ctorParameters: () => [], propDecorators: { activeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeColor", required: false }] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }] } });
10161
10192
 
10162
10193
  class ClxBrandComponent {
10194
+ _sanitizer = inject(DomSanitizer);
10163
10195
  logo = input.required(...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
10164
10196
  name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
10197
+ /** Optional rich-text brand name (e.g. per-word colored spans) — takes over from the plain
10198
+ * `name` text when set, which still backs the logo's `alt` and the fallback rendering. Caller
10199
+ * is responsible for only ever passing admin-authored content here, never unescaped user input —
10200
+ * this component trusts it as-is (bypassSecurityTrustHtml), same as ClxSocialIconComponent's
10201
+ * internal SVG markup. */
10202
+ nameHtml = input(undefined, ...(ngDevMode ? [{ debugName: "nameHtml" }] : /* istanbul ignore next */ []));
10165
10203
  description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
10166
10204
  collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
10205
+ _safeNameHtml = computed(() => this._sanitizer.bypassSecurityTrustHtml(this.nameHtml() ?? ''), ...(ngDevMode ? [{ debugName: "_safeNameHtml" }] : /* istanbul ignore next */ []));
10167
10206
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxBrandComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10168
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxBrandComponent, isStandalone: true, selector: "clx-brand", inputs: { logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: true, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, ngImport: i0, template: `
10207
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxBrandComponent, isStandalone: true, selector: "clx-brand", inputs: { logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: true, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, nameHtml: { classPropertyName: "nameHtml", publicName: "nameHtml", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, ngImport: i0, template: `
10169
10208
  <div [class]="collapsed() ? 'flex items-center justify-center py-4' : 'flex items-center gap-3 px-4 py-4'">
10170
10209
  <img [src]="logo()" [alt]="name()" class="h-8 w-8 shrink-0 object-contain" />
10171
10210
  @if (!collapsed()) {
10172
10211
  <div class="min-w-0 overflow-hidden">
10173
- <p class="text-white text-sm font-semibold truncate leading-tight">{{ name() }}</p>
10212
+ @if (nameHtml()) {
10213
+ <p class="text-sm font-semibold truncate leading-tight" [innerHTML]="_safeNameHtml()"></p>
10214
+ } @else {
10215
+ <p class="text-white text-sm font-semibold truncate leading-tight">{{ name() }}</p>
10216
+ }
10174
10217
  @if (description()) {
10175
10218
  <p class="text-slate-400 text-xs truncate leading-tight">{{ description() }}</p>
10176
10219
  }
@@ -10189,7 +10232,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10189
10232
  <img [src]="logo()" [alt]="name()" class="h-8 w-8 shrink-0 object-contain" />
10190
10233
  @if (!collapsed()) {
10191
10234
  <div class="min-w-0 overflow-hidden">
10192
- <p class="text-white text-sm font-semibold truncate leading-tight">{{ name() }}</p>
10235
+ @if (nameHtml()) {
10236
+ <p class="text-sm font-semibold truncate leading-tight" [innerHTML]="_safeNameHtml()"></p>
10237
+ } @else {
10238
+ <p class="text-white text-sm font-semibold truncate leading-tight">{{ name() }}</p>
10239
+ }
10193
10240
  @if (description()) {
10194
10241
  <p class="text-slate-400 text-xs truncate leading-tight">{{ description() }}</p>
10195
10242
  }
@@ -10201,7 +10248,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
10201
10248
  changeDetection: ChangeDetectionStrategy.OnPush,
10202
10249
  host: { class: 'block' },
10203
10250
  }]
10204
- }], propDecorators: { logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: true }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });
10251
+ }], propDecorators: { logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: true }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], nameHtml: [{ type: i0.Input, args: [{ isSignal: true, alias: "nameHtml", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });
10205
10252
 
10206
10253
  // ── Item geometry ──────────────────────────────────────────────────────────────
10207
10254
  const NAV_ITEM_BASE = 'flex items-center gap-3 cursor-pointer select-none';