@repobit/dex-system-design 0.24.19 → 0.24.20

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.24.20](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.24.19...@repobit/dex-system-design@0.24.20) (2026-09-24)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **DEX-1014:** new adjustments for Card component
11
+
12
+
6
13
  ## [0.24.19](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.24.18...@repobit/dex-system-design@0.24.19) (2026-09-23)
7
14
 
8
15
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@repobit/dex-system-design",
3
- "version": "0.24.19",
3
+ "version": "0.24.20",
4
4
  "description": "Design system based on Web Components.",
5
5
  "author": "Iordache Matei Cezar <miordache@bitdefender.com>",
6
6
  "homepage": "https://github.com/bitdefender/dex-core#readme",
@@ -76,8 +76,8 @@
76
76
  "url": "https://github.com/bitdefender/dex-core/issues"
77
77
  },
78
78
  "dependencies": {
79
- "@repobit/dex-store": "1.6.35",
80
- "@repobit/dex-store-elements": "2.1.5",
79
+ "@repobit/dex-store": "1.6.36",
80
+ "@repobit/dex-store-elements": "2.1.6",
81
81
  "lit": "^3.3.2"
82
82
  },
83
83
  "devDependencies": {
@@ -94,5 +94,5 @@
94
94
  "volta": {
95
95
  "node": "24.14.0"
96
96
  },
97
- "gitHead": "09e86b2eb429cec7fadc15b6aa945152ab500a19"
97
+ "gitHead": "c5b184f2837dad5acab88a931b12d3d51121ed57"
98
98
  }
@@ -50,6 +50,12 @@ export default css`
50
50
  gap: var(--spacing-8);
51
51
  }
52
52
 
53
+ /* Outline-variant sections get extra top padding above the header,
54
+ per the reference design. */
55
+ :host([variant="outline"]) .bd-header-light-carousel-s {
56
+ padding-top: 80px;
57
+ }
58
+
53
59
  .bd-light-carousel-s {
54
60
  display: flex;
55
61
  align-items: center;
@@ -95,6 +101,56 @@ export default css`
95
101
  background: #E4F2FF !important;
96
102
  }
97
103
 
104
+ /* === OUTLINE VARIANT — bordered, tinted, fully centered card. Set
105
+ variant="outline" on bd-card-section (propagates to items) or on an
106
+ individual bd-card-item to opt it in/out per-card. === */
107
+ .bd-light-box-outline {
108
+ background-color: var(--color-neutral-25);
109
+ border: 2px solid var(--color-blue-500);
110
+ border-radius: var(--radius-2xl, 1rem);
111
+ padding: 40px;
112
+ align-items: center !important;
113
+ justify-content: center !important;
114
+ text-align: center !important;
115
+ }
116
+
117
+ .bd-light-box-outline .bd-light-box-header-s {
118
+ align-items: center;
119
+ justify-content: center;
120
+ width: 100%;
121
+ }
122
+
123
+ .bd-light-box-outline .bd-light-title-badge-wrapper-s {
124
+ justify-content: center;
125
+ }
126
+
127
+ .bd-light-box-outline .bd-card-title-group {
128
+ align-items: center;
129
+ text-align: center;
130
+ margin-top: 60px;
131
+ }
132
+
133
+ .bd-light-box-outline .bd-card-title-group bd-h {
134
+ color: var(--color-blue-500, #006dff);
135
+ text-align: center;
136
+ }
137
+
138
+ .bd-light-box-outline .bd-card-item-subtitle,
139
+ .bd-light-box-outline .bd-card-content-wrapper p,
140
+ .bd-light-box-outline .bd-card-content-wrapper ::slotted(*) {
141
+ color: var(--color-neutral-700);
142
+ text-align: center;
143
+ }
144
+
145
+ .bd-light-box-outline .bd-card-content-wrapper {
146
+ align-items: center;
147
+ text-align: center;
148
+ }
149
+
150
+ .bd-light-box-outline .bd-card-cta-wrapper {
151
+ justify-content: center;
152
+ }
153
+
98
154
  .bd-light-box-center {
99
155
  align-items: center !important;
100
156
  justify-content: center !important;
@@ -9,6 +9,13 @@ class Card extends LitElement {
9
9
  title : { type: String },
10
10
  subtitle : { type: String },
11
11
  bgBlue : { type: Boolean, reflect: true, attribute: "bg-blue" },
12
+ // "" (default — existing grey-box carousel look) | "outline" — bordered,
13
+ // centered cards with a light-blue tint, blue title and centered icon,
14
+ // matching the reference design. Propagated automatically to every
15
+ // slotted bd-card-item (see _onSlotChange) so callers only set it once,
16
+ // on the section, unless a specific item needs to opt out by setting
17
+ // its own variant attribute explicitly.
18
+ variant : { type: String, reflect: true },
12
19
  _itemCount: { state: true }
13
20
  };
14
21
 
@@ -17,6 +24,7 @@ class Card extends LitElement {
17
24
  this.title = "";
18
25
  this.subtitle = "";
19
26
  this.bgBlue = false;
27
+ this.variant = "";
20
28
  this._itemCount = 0;
21
29
  this._resizeObserver = null;
22
30
  }
@@ -47,8 +55,26 @@ class Card extends LitElement {
47
55
  this.style.setProperty("--bd-card-width", `${cardW}px`);
48
56
  }
49
57
 
58
+ // Propagates this.variant onto every slotted bd-card-item that didn't
59
+ // itself declare a variant attribute in its ORIGINAL markup. We can't use
60
+ // item.hasAttribute("variant") here — CardItem's own `variant` property
61
+ // has reflect:true, so Lit reflects its default "" onto the attribute on
62
+ // first render, meaning hasAttribute("variant") becomes true for EVERY
63
+ // item almost immediately, even ones the author never touched. Instead
64
+ // we rely on item._authorSetVariant, captured in CardItem's constructor
65
+ // (before Lit's own reflection has a chance to run) — see below.
66
+ _propagateVariant() {
67
+ if (!this.variant) return;
68
+ this.querySelectorAll("bd-card-item").forEach((item) => {
69
+ if (!item._authorSetVariant) {
70
+ item.variant = this.variant;
71
+ }
72
+ });
73
+ }
74
+
50
75
  _onSlotChange = () => {
51
76
  this._itemCount = this.querySelectorAll("bd-card-item").length;
77
+ this._propagateVariant();
52
78
  this._updateCardWidth();
53
79
  this.requestUpdate();
54
80
  this._equalizeHeights();
@@ -160,6 +186,7 @@ class Card extends LitElement {
160
186
  }
161
187
 
162
188
  await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
189
+ this._propagateVariant();
163
190
  this._updateCardWidth();
164
191
  this._equalizeHeights();
165
192
 
@@ -208,38 +235,61 @@ class CardItem extends LitElement {
208
235
  icon : { type: String },
209
236
  align : { type: String },
210
237
  bgBlue : { type: Boolean, reflect: true, attribute: "bg-blue" },
211
- ctaAlign: { type: String, attribute: "cta-align" }
238
+ ctaAlign: { type: String, attribute: "cta-align" },
239
+ // "" (default) | "outline" — see Card.variant above. Reflected so
240
+ // card.css.js can target it with :host([variant="outline"]).
241
+ variant : { type: String, reflect: true }
212
242
  };
213
243
 
214
244
  constructor() {
215
245
  super();
246
+ // Captured BEFORE Lit's own property-to-attribute reflection runs (that
247
+ // happens on first update/render, not here). At this point the DOM
248
+ // parser has already set any attribute the author wrote in markup, so
249
+ // this reliably answers "did the author explicitly set variant on this
250
+ // element", independent of whatever default value we assign below.
251
+ this._authorSetVariant = this.hasAttribute("variant");
252
+
216
253
  this.title = "";
217
254
  this.subtitle = "";
218
255
  this.icon = "";
219
256
  this.align = "start";
220
257
  this.bgBlue = false;
221
258
  this.ctaAlign = "start";
259
+ this.variant = "";
222
260
  }
223
261
 
224
262
  _renderIcon() {
225
263
  const iconEl = this.querySelector("[slot='icon']");
264
+ const isOutline = this.variant === "outline";
265
+ const iconW = isOutline ? 65 : 48;
266
+ const iconH = isOutline ? 75 : 48;
226
267
 
227
268
  if (iconEl) {
228
269
  const clone = iconEl.cloneNode(true);
229
270
 
230
- clone.style.maxWidth = "48px";
231
- clone.style.maxHeight = "48px";
232
- clone.style.width = "48px";
233
- clone.style.height = "48px";
271
+ // The icon components (bd-globe-icon etc.) size their inner <svg>
272
+ // from their own width/height attributes, not from CSS on the host —
273
+ // setting only clone.style.width/height left the SVG's actual
274
+ // width="48" height="48" attributes untouched, so nothing visibly
275
+ // changed. Overwrite the attributes themselves for anything that
276
+ // looks like an icon component (custom element) or a raw <svg>.
277
+ clone.setAttribute("width", iconW);
278
+ clone.setAttribute("height", iconH);
279
+
280
+ clone.style.maxWidth = `${iconW}px`;
281
+ clone.style.maxHeight = `${iconH}px`;
282
+ clone.style.width = `${iconW}px`;
283
+ clone.style.height = `${iconH}px`;
234
284
  clone.style.objectFit = "contain";
235
285
  clone.style.display = "block";
236
286
 
237
287
  const innerImg = clone.querySelector("img");
238
288
  if (innerImg) {
239
- innerImg.style.maxWidth = "48px";
240
- innerImg.style.maxHeight = "48px";
241
- innerImg.style.width = "48px";
242
- innerImg.style.height = "48px";
289
+ innerImg.style.maxWidth = `${iconW}px`;
290
+ innerImg.style.maxHeight = `${iconH}px`;
291
+ innerImg.style.width = `${iconW}px`;
292
+ innerImg.style.height = `${iconH}px`;
243
293
  innerImg.style.objectFit = "contain";
244
294
  innerImg.style.display = "block";
245
295
  innerImg.removeAttribute("width");
@@ -254,6 +304,7 @@ class CardItem extends LitElement {
254
304
  src="${this.icon}"
255
305
  alt="icon"
256
306
  class="bd-light-icon-s"
307
+ style="width: ${iconW}px; height: ${iconH}px;"
257
308
  />`;
258
309
  }
259
310
 
@@ -272,7 +323,8 @@ class CardItem extends LitElement {
272
323
  }
273
324
 
274
325
  render() {
275
- const isCentered = this.align === "center";
326
+ const isOutline = this.variant === "outline";
327
+ const isCentered = this.align === "center" || isOutline;
276
328
  const hasContent = this._hasContent();
277
329
  const hasCtaSlot = !!this.querySelector("[slot='cta']");
278
330
  const ctaJustify = this.ctaAlign === "center"
@@ -285,7 +337,8 @@ class CardItem extends LitElement {
285
337
  <div
286
338
  class="bd-light-box-s
287
339
  ${isCentered ? "bd-light-box-center" : ""}
288
- ${this.bgBlue ? "bd-light-box-blue" : ""}"
340
+ ${this.bgBlue ? "bd-light-box-blue" : ""}
341
+ ${isOutline ? "bd-light-box-outline" : ""}"
289
342
  >
290
343
  <div class="bd-light-box-header-s ${isCentered ? "bd-light-box-header-center" : ""}">
291
344
  ${this._renderIcon()}
@@ -27,6 +27,13 @@ Grid columns are calculated automatically:
27
27
  | 7–8 | 4 | 4+3, 4+4 |
28
28
  | 9 | 3 | 3+3+3 |
29
29
  | 10+ | 4 | 4+4+... |
30
+
31
+ ### Variants
32
+ \`variant="outline"\` on \`bd-card-section\` switches every slotted \`bd-card-item\`
33
+ to a bordered, light-blue-tinted, centered card style (blue title, centered
34
+ icon/text) — set it once on the section, it propagates to all items
35
+ automatically. Leaving \`variant\` unset keeps the existing grey-box look.
36
+ An individual \`bd-card-item\` can opt out with \`variant=""\` explicitly.
30
37
  `
31
38
  }
32
39
  }
@@ -324,6 +331,54 @@ export const MobileView = {
324
331
  </bd-card-section>
325
332
  ` };
326
333
 
334
+ // ─── Outline Variant ────────────────────────────────────────────────────────
335
+
336
+ export const OutlineVariant = {
337
+ name : 'Outline Variant — Trusted For The AI Era',
338
+ render: () => html`
339
+ <bd-card-section
340
+ title="Trusted For The AI Era"
341
+ subtitle="Pioneering AI in Cybersecurity since 2008."
342
+ variant="outline"
343
+ >
344
+ <bd-card-item title="Transparency">
345
+ <bd-individual-icon slot="icon" width="48" height="48" color="#006DFF"></bd-individual-icon>
346
+ <bd-p>We provide clear information about how our AI makes security decisions and what data it uses, balancing technical transparency with usability.</bd-p>
347
+ </bd-card-item>
348
+ <bd-card-item title="Privacy by Design">
349
+ <bd-globe-icon slot="icon" width="48" height="48" color="#006DFF"></bd-globe-icon>
350
+ <bd-p>We implement privacy-preserving techniques like federated learning and differential privacy to minimize data exposure while maintaining AI effectiveness.</bd-p>
351
+ </bd-card-item>
352
+ <bd-card-item title="Human Guided AI Protection">
353
+ <bd-family-icon slot="icon" width="48" height="48" color="#006DFF"></bd-family-icon>
354
+ <bd-p>While our AI is powerful, we augment it with the deep expertise of Bitdefender Labs.</bd-p>
355
+ </bd-card-item>
356
+ </bd-card-section>
357
+ `,
358
+ parameters: { docs: { description: { story: '`variant="outline"` pe `bd-card-section` — se propagă automat la toate cardurile: contur albastru subțire, fundal albastru foarte deschis, titlu albastru, conținut centrat.' } } }
359
+ };
360
+
361
+ export const OutlineVariantMixed = {
362
+ name : 'Outline Variant — Mixed With Default',
363
+ render: () => html`
364
+ <bd-card-section title="Mixed Variants" variant="outline">
365
+ <bd-card-item title="Outline Card One">
366
+ <bd-individual-icon slot="icon" width="48" height="48" color="#006DFF"></bd-individual-icon>
367
+ <bd-p>This card inherits the outline variant from the section.</bd-p>
368
+ </bd-card-item>
369
+ <bd-card-item title="Opted-out Card" variant="">
370
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
371
+ <bd-p>This card explicitly sets variant="" to opt out and keep the default grey-box look.</bd-p>
372
+ </bd-card-item>
373
+ <bd-card-item title="Outline Card Two">
374
+ <bd-machine-learning-icon slot="icon" width="48" height="48" color="#006DFF"></bd-machine-learning-icon>
375
+ <bd-p>This card also inherits the outline variant.</bd-p>
376
+ </bd-card-item>
377
+ </bd-card-section>
378
+ `,
379
+ parameters: { docs: { description: { story: 'Un card poate seta `variant=""` explicit ca să rămână pe stilul default, chiar dacă secțiunea are `variant="outline"`.' } } }
380
+ };
381
+
327
382
  // ─── Playground ───────────────────────────────────────────────────────────────
328
383
 
329
384
  export const Playground = {
@@ -331,13 +386,21 @@ export const Playground = {
331
386
  args: {
332
387
  sectionTitle : 'Why Bitdefender',
333
388
  sectionSubtitle: '',
389
+ sectionVariant : '',
334
390
  itemTitle : 'AI Protection',
335
391
  align : 'start',
336
392
  bgBlue : false,
337
393
  ctaAlign : 'start'
338
394
  },
395
+ argTypes: {
396
+ sectionVariant: {
397
+ control : { type: 'select' },
398
+ options : ['', 'outline'],
399
+ description: 'bd-card-section variant — propagates to all items'
400
+ }
401
+ },
339
402
  render: (args) => html`
340
- <bd-card-section title="${args.sectionTitle}" subtitle="${args.sectionSubtitle}">
403
+ <bd-card-section title="${args.sectionTitle}" subtitle="${args.sectionSubtitle}" variant="${args.sectionVariant}">
341
404
  <bd-card-item
342
405
  title="${args.itemTitle}"
343
406
  align="${args.align}"
@@ -360,5 +423,5 @@ export const Playground = {
360
423
  </bd-card-item>
361
424
  </bd-card-section>
362
425
  `,
363
- parameters: { docs: { description: { story: 'Playground interactiv.' } } }
426
+ parameters: { docs: { description: { story: 'Playground interactiv — folosește `sectionVariant` din Controls ca să testezi `variant="outline"`.' } } }
364
427
  };