@duskmoon-dev/el-card 0.2.0 → 0.4.0

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/dist/cjs/index.js CHANGED
@@ -36,6 +36,13 @@ module.exports = __toCommonJS(exports_src);
36
36
 
37
37
  // src/el-dm-card.ts
38
38
  var import_el_core = require("@duskmoon-dev/el-core");
39
+ var import_card = require("@duskmoon-dev/core/components/card");
40
+ var VARIANT_CLASSES = {
41
+ elevated: "card-elevated",
42
+ outlined: "card-bordered",
43
+ filled: ""
44
+ };
45
+ var coreStyles = import_card.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
39
46
  var styles = import_el_core.css`
40
47
  :host {
41
48
  display: block;
@@ -45,155 +52,56 @@ var styles = import_el_core.css`
45
52
  display: none !important;
46
53
  }
47
54
 
48
- .card {
49
- display: flex;
50
- flex-direction: column;
51
- border-radius: var(--dm-card-border-radius, var(--dm-radius-lg, 0.75rem));
52
- background-color: var(--dm-card-background, white);
53
- overflow: hidden;
54
- transition:
55
- box-shadow var(--dm-transition-normal, 200ms ease),
56
- transform var(--dm-transition-normal, 200ms ease);
57
- }
55
+ /* Import core card styles */
56
+ ${coreStyles}
58
57
 
59
- /* Elevated variant (default) */
60
- :host(:not([variant])) .card,
61
- :host([variant='elevated']) .card {
62
- box-shadow: var(--dm-card-shadow, var(--dm-shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1)));
63
- }
58
+ /* Web component specific adjustments */
64
59
 
65
- /* Outlined variant */
66
- :host([variant='outlined']) .card {
67
- border: 1px solid var(--dm-card-border-color, var(--dm-gray-200, #e5e7eb));
68
- box-shadow: none;
69
- }
70
-
71
- /* Filled variant */
72
- :host([variant='filled']) .card {
73
- background-color: var(--dm-card-background, var(--dm-gray-50, #f9fafb));
74
- box-shadow: none;
75
- }
76
-
77
- /* Interactive styles */
78
- :host([interactive]) .card {
79
- cursor: pointer;
80
- }
81
-
82
- :host([interactive]) .card:hover {
83
- transform: translateY(-2px);
84
- }
85
-
86
- :host([interactive][variant='elevated']) .card:hover,
87
- :host([interactive]:not([variant])) .card:hover {
88
- box-shadow: var(--dm-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
89
- }
90
-
91
- :host([interactive][variant='outlined']) .card:hover {
92
- border-color: var(--dm-primary, #3b82f6);
93
- }
94
-
95
- :host([interactive][variant='filled']) .card:hover {
96
- background-color: var(--dm-gray-100, #f3f4f6);
97
- }
98
-
99
- :host([interactive]) .card:focus-visible {
100
- outline: none;
101
- box-shadow: var(--dm-focus-ring-offset, 0 0 0 2px white, 0 0 0 4px var(--dm-primary, #3b82f6));
102
- }
103
-
104
- /* Media slot */
105
- .media {
60
+ /* Media slot handling */
61
+ .card-image {
106
62
  display: none;
107
63
  }
108
64
 
109
- .media.has-content {
65
+ .card-image.has-content {
110
66
  display: block;
111
67
  }
112
68
 
113
- .media ::slotted(*) {
69
+ .card-image ::slotted(*) {
114
70
  display: block;
115
71
  width: 100%;
116
72
  object-fit: cover;
117
73
  }
118
74
 
119
- /* Header */
120
- .header {
75
+ /* Header slot handling */
76
+ .card-header {
121
77
  display: none;
122
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
123
- padding-bottom: 0;
124
- }
125
-
126
- .header.has-content {
127
- display: block;
128
- }
129
-
130
- /* Body */
131
- .body {
132
- flex: 1;
133
78
  }
134
79
 
135
- /* Padding variants */
136
- :host(:not([padding])) .body,
137
- :host([padding='md']) .body {
138
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
139
- }
140
-
141
- :host([padding='none']) .body {
142
- padding: 0;
143
- }
144
-
145
- :host([padding='sm']) .body {
146
- padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));
147
- }
148
-
149
- :host([padding='lg']) .body {
150
- padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));
151
- }
152
-
153
- :host(:not([padding])) .header,
154
- :host([padding='md']) .header {
155
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
156
- padding-bottom: 0;
157
- }
158
-
159
- :host([padding='sm']) .header {
160
- padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));
161
- padding-bottom: 0;
162
- }
163
-
164
- :host([padding='lg']) .header {
165
- padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));
166
- padding-bottom: 0;
80
+ .card-header.has-content {
81
+ display: flex;
167
82
  }
168
83
 
169
- /* Footer */
170
- .footer {
84
+ /* Footer slot handling */
85
+ .card-footer {
171
86
  display: none;
172
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
173
- padding-top: 0;
174
- border-top: 1px solid var(--dm-gray-100, #f3f4f6);
175
- margin-top: var(--dm-spacing-md, 1rem);
176
87
  }
177
88
 
178
- .footer.has-content {
179
- display: block;
89
+ .card-footer.has-content {
90
+ display: flex;
180
91
  }
181
92
 
182
- :host([padding='sm']) .footer {
183
- padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));
184
- padding-top: 0;
185
- margin-top: var(--dm-spacing-sm, 0.5rem);
93
+ /* Padding variants */
94
+ :host([padding='none']) .card-body {
95
+ padding: 0;
186
96
  }
187
97
 
188
- :host([padding='lg']) .footer {
189
- padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));
190
- padding-top: 0;
191
- margin-top: var(--dm-spacing-lg, 1.5rem);
98
+ :host([padding='lg']) .card-body {
99
+ --card-p: 2rem;
192
100
  }
193
101
 
194
- :host([padding='none']) .footer {
195
- padding: var(--dm-spacing-md, 1rem);
196
- margin-top: 0;
102
+ :host([padding='lg']) .card-header,
103
+ :host([padding='lg']) .card-footer {
104
+ --card-p: 2rem;
197
105
  }
198
106
  `;
199
107
 
@@ -216,8 +124,15 @@ class ElDmCard extends import_el_core.BaseElement {
216
124
  }
217
125
  _handleSlotChange(event) {
218
126
  const slot = event.target;
219
- const slotName = slot.name || "body";
220
- const wrapper = this.shadowRoot.querySelector(`.${slotName}`);
127
+ const slotName = slot.name;
128
+ const wrapperMap = {
129
+ media: "card-image",
130
+ header: "card-header",
131
+ footer: "card-footer",
132
+ "": "card-body"
133
+ };
134
+ const wrapperClass = wrapperMap[slotName] || "card-body";
135
+ const wrapper = this.shadowRoot.querySelector(`.${wrapperClass}`);
221
136
  if (wrapper) {
222
137
  const hasContent = slot.assignedNodes().length > 0;
223
138
  wrapper.classList.toggle("has-content", hasContent);
@@ -236,19 +151,33 @@ class ElDmCard extends import_el_core.BaseElement {
236
151
  });
237
152
  }
238
153
  }
154
+ _getCardClasses() {
155
+ const classes = ["card"];
156
+ if (this.variant && VARIANT_CLASSES[this.variant]) {
157
+ classes.push(VARIANT_CLASSES[this.variant]);
158
+ }
159
+ if (this.interactive) {
160
+ classes.push("card-interactive");
161
+ }
162
+ if (this.padding === "sm") {
163
+ classes.push("card-compact");
164
+ }
165
+ return classes.filter(Boolean).join(" ");
166
+ }
239
167
  render() {
168
+ const cardClasses = this._getCardClasses();
240
169
  return `
241
- <div class="card" part="card">
242
- <div class="media" part="media">
170
+ <div class="${cardClasses}" part="card">
171
+ <div class="card-image" part="media">
243
172
  <slot name="media"></slot>
244
173
  </div>
245
- <div class="header" part="header">
174
+ <div class="card-header" part="header">
246
175
  <slot name="header"></slot>
247
176
  </div>
248
- <div class="body" part="body">
177
+ <div class="card-body" part="body">
249
178
  <slot></slot>
250
179
  </div>
251
- <div class="footer" part="footer">
180
+ <div class="card-footer" part="footer">
252
181
  <slot name="footer"></slot>
253
182
  </div>
254
183
  </div>
@@ -263,5 +192,5 @@ function register() {
263
192
  }
264
193
  }
265
194
 
266
- //# debugId=CB01C6530EFE487964756E2164756E21
195
+ //# debugId=E32B21B531428C6264756E2164756E21
267
196
  //# sourceMappingURL=index.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/el-dm-card.ts", "../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * DuskMoon Card Element\n *\n * A container component with header, body, and footer sections.\n *\n * @element el-dm-card\n *\n * @attr {string} variant - Card variant: elevated, outlined, filled\n * @attr {boolean} interactive - Whether the card is clickable/hoverable\n * @attr {string} padding - Padding size: none, sm, md, lg\n *\n * @slot - Default slot for card body content\n * @slot header - Card header content\n * @slot footer - Card footer content\n * @slot media - Media content (image/video) at the top of card\n *\n * @csspart card - The main card container\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n * @csspart media - The media section\n *\n * @fires click - Fired when interactive card is clicked\n *\n * @cssprop --dm-card-padding - Card padding\n * @cssprop --dm-card-border-radius - Border radius\n * @cssprop --dm-card-background - Background color\n * @cssprop --dm-card-border-color - Border color (for outlined variant)\n * @cssprop --dm-card-shadow - Box shadow (for elevated variant)\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\n\n/**\n * Card variant options\n */\nexport type CardVariant = 'elevated' | 'outlined' | 'filled';\n\n/**\n * Card padding options\n */\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nconst styles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n .card {\n display: flex;\n flex-direction: column;\n border-radius: var(--dm-card-border-radius, var(--dm-radius-lg, 0.75rem));\n background-color: var(--dm-card-background, white);\n overflow: hidden;\n transition:\n box-shadow var(--dm-transition-normal, 200ms ease),\n transform var(--dm-transition-normal, 200ms ease);\n }\n\n /* Elevated variant (default) */\n :host(:not([variant])) .card,\n :host([variant='elevated']) .card {\n box-shadow: var(--dm-card-shadow, var(--dm-shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1)));\n }\n\n /* Outlined variant */\n :host([variant='outlined']) .card {\n border: 1px solid var(--dm-card-border-color, var(--dm-gray-200, #e5e7eb));\n box-shadow: none;\n }\n\n /* Filled variant */\n :host([variant='filled']) .card {\n background-color: var(--dm-card-background, var(--dm-gray-50, #f9fafb));\n box-shadow: none;\n }\n\n /* Interactive styles */\n :host([interactive]) .card {\n cursor: pointer;\n }\n\n :host([interactive]) .card:hover {\n transform: translateY(-2px);\n }\n\n :host([interactive][variant='elevated']) .card:hover,\n :host([interactive]:not([variant])) .card:hover {\n box-shadow: var(--dm-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));\n }\n\n :host([interactive][variant='outlined']) .card:hover {\n border-color: var(--dm-primary, #3b82f6);\n }\n\n :host([interactive][variant='filled']) .card:hover {\n background-color: var(--dm-gray-100, #f3f4f6);\n }\n\n :host([interactive]) .card:focus-visible {\n outline: none;\n box-shadow: var(--dm-focus-ring-offset, 0 0 0 2px white, 0 0 0 4px var(--dm-primary, #3b82f6));\n }\n\n /* Media slot */\n .media {\n display: none;\n }\n\n .media.has-content {\n display: block;\n }\n\n .media ::slotted(*) {\n display: block;\n width: 100%;\n object-fit: cover;\n }\n\n /* Header */\n .header {\n display: none;\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n padding-bottom: 0;\n }\n\n .header.has-content {\n display: block;\n }\n\n /* Body */\n .body {\n flex: 1;\n }\n\n /* Padding variants */\n :host(:not([padding])) .body,\n :host([padding='md']) .body {\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n }\n\n :host([padding='none']) .body {\n padding: 0;\n }\n\n :host([padding='sm']) .body {\n padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));\n }\n\n :host([padding='lg']) .body {\n padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));\n }\n\n :host(:not([padding])) .header,\n :host([padding='md']) .header {\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n padding-bottom: 0;\n }\n\n :host([padding='sm']) .header {\n padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));\n padding-bottom: 0;\n }\n\n :host([padding='lg']) .header {\n padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));\n padding-bottom: 0;\n }\n\n /* Footer */\n .footer {\n display: none;\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n padding-top: 0;\n border-top: 1px solid var(--dm-gray-100, #f3f4f6);\n margin-top: var(--dm-spacing-md, 1rem);\n }\n\n .footer.has-content {\n display: block;\n }\n\n :host([padding='sm']) .footer {\n padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));\n padding-top: 0;\n margin-top: var(--dm-spacing-sm, 0.5rem);\n }\n\n :host([padding='lg']) .footer {\n padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));\n padding-top: 0;\n margin-top: var(--dm-spacing-lg, 1.5rem);\n }\n\n :host([padding='none']) .footer {\n padding: var(--dm-spacing-md, 1rem);\n margin-top: 0;\n }\n`;\n\nexport class ElDmCard extends BaseElement {\n static properties = {\n variant: { type: String, reflect: true },\n interactive: { type: Boolean, reflect: true },\n padding: { type: String, reflect: true },\n };\n\n /** Card variant */\n declare variant: CardVariant;\n\n /** Whether the card is interactive */\n declare interactive: boolean;\n\n /** Card padding size */\n declare padding: CardPadding;\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n\n // Set up slot change listeners for conditional display\n this.shadowRoot.addEventListener('slotchange', this._handleSlotChange.bind(this));\n\n // Set up click handler for interactive cards\n if (this.interactive) {\n this._setupInteractive();\n }\n }\n\n /**\n * Handle slot content changes\n */\n private _handleSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const slotName = slot.name || 'body';\n const wrapper = this.shadowRoot.querySelector(`.${slotName}`);\n\n if (wrapper) {\n const hasContent = slot.assignedNodes().length > 0;\n wrapper.classList.toggle('has-content', hasContent);\n }\n }\n\n /**\n * Set up interactive card behavior\n */\n private _setupInteractive(): void {\n const card = this.shadowRoot.querySelector('.card') as HTMLElement;\n if (card) {\n card.setAttribute('tabindex', '0');\n card.setAttribute('role', 'button');\n\n card.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.emit('click');\n }\n });\n }\n }\n\n render(): string {\n return `\n <div class=\"card\" part=\"card\">\n <div class=\"media\" part=\"media\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"header\" part=\"header\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"footer\" part=\"footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n `;\n }\n}\n",
5
+ "/**\n * DuskMoon Card Element\n *\n * A container component with header, body, and footer sections.\n * Uses styles from @duskmoon-dev/core for consistent theming.\n *\n * @element el-dm-card\n *\n * @attr {string} variant - Card variant: elevated, outlined, filled\n * @attr {boolean} interactive - Whether the card is clickable/hoverable\n * @attr {string} padding - Padding size: none, sm, md, lg\n *\n * @slot - Default slot for card body content\n * @slot header - Card header content\n * @slot footer - Card footer content\n * @slot media - Media content (image/video) at the top of card\n *\n * @csspart card - The main card container\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n * @csspart media - The media section\n *\n * @fires click - Fired when interactive card is clicked\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\nimport { css as cardCSS } from '@duskmoon-dev/core/components/card';\n\n/**\n * Card variant options\n */\nexport type CardVariant = 'elevated' | 'outlined' | 'filled';\n\n/**\n * Card padding options\n */\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\n// Map of variant attribute values to CSS classes\nconst VARIANT_CLASSES: Record<string, string> = {\n elevated: 'card-elevated',\n outlined: 'card-bordered',\n filled: '', // default card style\n};\n\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = cardCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\n\nconst styles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n /* Import core card styles */\n ${coreStyles}\n\n /* Web component specific adjustments */\n\n /* Media slot handling */\n .card-image {\n display: none;\n }\n\n .card-image.has-content {\n display: block;\n }\n\n .card-image ::slotted(*) {\n display: block;\n width: 100%;\n object-fit: cover;\n }\n\n /* Header slot handling */\n .card-header {\n display: none;\n }\n\n .card-header.has-content {\n display: flex;\n }\n\n /* Footer slot handling */\n .card-footer {\n display: none;\n }\n\n .card-footer.has-content {\n display: flex;\n }\n\n /* Padding variants */\n :host([padding='none']) .card-body {\n padding: 0;\n }\n\n :host([padding='lg']) .card-body {\n --card-p: 2rem;\n }\n\n :host([padding='lg']) .card-header,\n :host([padding='lg']) .card-footer {\n --card-p: 2rem;\n }\n`;\n\nexport class ElDmCard extends BaseElement {\n static properties = {\n variant: { type: String, reflect: true },\n interactive: { type: Boolean, reflect: true },\n padding: { type: String, reflect: true },\n };\n\n /** Card variant */\n declare variant: CardVariant;\n\n /** Whether the card is interactive */\n declare interactive: boolean;\n\n /** Card padding size */\n declare padding: CardPadding;\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n\n // Set up slot change listeners for conditional display\n this.shadowRoot.addEventListener('slotchange', this._handleSlotChange.bind(this));\n\n // Set up click handler for interactive cards\n if (this.interactive) {\n this._setupInteractive();\n }\n }\n\n /**\n * Handle slot content changes\n */\n private _handleSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const slotName = slot.name;\n\n // Map slot names to wrapper class names\n const wrapperMap: Record<string, string> = {\n media: 'card-image',\n header: 'card-header',\n footer: 'card-footer',\n '': 'card-body',\n };\n\n const wrapperClass = wrapperMap[slotName] || 'card-body';\n const wrapper = this.shadowRoot.querySelector(`.${wrapperClass}`);\n\n if (wrapper) {\n const hasContent = slot.assignedNodes().length > 0;\n wrapper.classList.toggle('has-content', hasContent);\n }\n }\n\n /**\n * Set up interactive card behavior\n */\n private _setupInteractive(): void {\n const card = this.shadowRoot.querySelector('.card') as HTMLElement;\n if (card) {\n card.setAttribute('tabindex', '0');\n card.setAttribute('role', 'button');\n\n card.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.emit('click');\n }\n });\n }\n }\n\n /**\n * Build CSS class string for the card\n */\n private _getCardClasses(): string {\n const classes = ['card'];\n\n // Add variant class\n if (this.variant && VARIANT_CLASSES[this.variant]) {\n classes.push(VARIANT_CLASSES[this.variant]);\n }\n\n // Add interactive class\n if (this.interactive) {\n classes.push('card-interactive');\n }\n\n // Add compact class for small padding\n if (this.padding === 'sm') {\n classes.push('card-compact');\n }\n\n return classes.filter(Boolean).join(' ');\n }\n\n render(): string {\n const cardClasses = this._getCardClasses();\n\n return `\n <div class=\"${cardClasses}\" part=\"card\">\n <div class=\"card-image\" part=\"media\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-header\" part=\"header\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n `;\n }\n}\n",
6
6
  "/**\n * @duskmoon-dev/el-card\n *\n * DuskMoon Card custom element\n */\n\nimport { ElDmCard } from './el-dm-card.js';\n\nexport { ElDmCard };\nexport type { CardVariant, CardPadding } from './el-dm-card.js';\n\n/**\n * Register the el-dm-card custom element\n *\n * @example\n * ```ts\n * import { register } from '@duskmoon-dev/el-card';\n * register();\n * ```\n */\nexport function register(): void {\n if (!customElements.get('el-dm-card')) {\n customElements.define('el-dm-card', ElDmCard);\n }\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "CB01C6530EFE487964756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "E32B21B531428C6264756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -36,6 +36,13 @@ module.exports = __toCommonJS(exports_src);
36
36
 
37
37
  // src/el-dm-card.ts
38
38
  var import_el_core = require("@duskmoon-dev/el-core");
39
+ var import_card = require("@duskmoon-dev/core/components/card");
40
+ var VARIANT_CLASSES = {
41
+ elevated: "card-elevated",
42
+ outlined: "card-bordered",
43
+ filled: ""
44
+ };
45
+ var coreStyles = import_card.css.replace(/@layer\s+components\s*\{/, "").replace(/\}\s*$/, "");
39
46
  var styles = import_el_core.css`
40
47
  :host {
41
48
  display: block;
@@ -45,155 +52,56 @@ var styles = import_el_core.css`
45
52
  display: none !important;
46
53
  }
47
54
 
48
- .card {
49
- display: flex;
50
- flex-direction: column;
51
- border-radius: var(--dm-card-border-radius, var(--dm-radius-lg, 0.75rem));
52
- background-color: var(--dm-card-background, white);
53
- overflow: hidden;
54
- transition:
55
- box-shadow var(--dm-transition-normal, 200ms ease),
56
- transform var(--dm-transition-normal, 200ms ease);
57
- }
55
+ /* Import core card styles */
56
+ ${coreStyles}
58
57
 
59
- /* Elevated variant (default) */
60
- :host(:not([variant])) .card,
61
- :host([variant='elevated']) .card {
62
- box-shadow: var(--dm-card-shadow, var(--dm-shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1)));
63
- }
58
+ /* Web component specific adjustments */
64
59
 
65
- /* Outlined variant */
66
- :host([variant='outlined']) .card {
67
- border: 1px solid var(--dm-card-border-color, var(--dm-gray-200, #e5e7eb));
68
- box-shadow: none;
69
- }
70
-
71
- /* Filled variant */
72
- :host([variant='filled']) .card {
73
- background-color: var(--dm-card-background, var(--dm-gray-50, #f9fafb));
74
- box-shadow: none;
75
- }
76
-
77
- /* Interactive styles */
78
- :host([interactive]) .card {
79
- cursor: pointer;
80
- }
81
-
82
- :host([interactive]) .card:hover {
83
- transform: translateY(-2px);
84
- }
85
-
86
- :host([interactive][variant='elevated']) .card:hover,
87
- :host([interactive]:not([variant])) .card:hover {
88
- box-shadow: var(--dm-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
89
- }
90
-
91
- :host([interactive][variant='outlined']) .card:hover {
92
- border-color: var(--dm-primary, #3b82f6);
93
- }
94
-
95
- :host([interactive][variant='filled']) .card:hover {
96
- background-color: var(--dm-gray-100, #f3f4f6);
97
- }
98
-
99
- :host([interactive]) .card:focus-visible {
100
- outline: none;
101
- box-shadow: var(--dm-focus-ring-offset, 0 0 0 2px white, 0 0 0 4px var(--dm-primary, #3b82f6));
102
- }
103
-
104
- /* Media slot */
105
- .media {
60
+ /* Media slot handling */
61
+ .card-image {
106
62
  display: none;
107
63
  }
108
64
 
109
- .media.has-content {
65
+ .card-image.has-content {
110
66
  display: block;
111
67
  }
112
68
 
113
- .media ::slotted(*) {
69
+ .card-image ::slotted(*) {
114
70
  display: block;
115
71
  width: 100%;
116
72
  object-fit: cover;
117
73
  }
118
74
 
119
- /* Header */
120
- .header {
75
+ /* Header slot handling */
76
+ .card-header {
121
77
  display: none;
122
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
123
- padding-bottom: 0;
124
- }
125
-
126
- .header.has-content {
127
- display: block;
128
- }
129
-
130
- /* Body */
131
- .body {
132
- flex: 1;
133
78
  }
134
79
 
135
- /* Padding variants */
136
- :host(:not([padding])) .body,
137
- :host([padding='md']) .body {
138
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
139
- }
140
-
141
- :host([padding='none']) .body {
142
- padding: 0;
143
- }
144
-
145
- :host([padding='sm']) .body {
146
- padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));
147
- }
148
-
149
- :host([padding='lg']) .body {
150
- padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));
151
- }
152
-
153
- :host(:not([padding])) .header,
154
- :host([padding='md']) .header {
155
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
156
- padding-bottom: 0;
157
- }
158
-
159
- :host([padding='sm']) .header {
160
- padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));
161
- padding-bottom: 0;
162
- }
163
-
164
- :host([padding='lg']) .header {
165
- padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));
166
- padding-bottom: 0;
80
+ .card-header.has-content {
81
+ display: flex;
167
82
  }
168
83
 
169
- /* Footer */
170
- .footer {
84
+ /* Footer slot handling */
85
+ .card-footer {
171
86
  display: none;
172
- padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));
173
- padding-top: 0;
174
- border-top: 1px solid var(--dm-gray-100, #f3f4f6);
175
- margin-top: var(--dm-spacing-md, 1rem);
176
87
  }
177
88
 
178
- .footer.has-content {
179
- display: block;
89
+ .card-footer.has-content {
90
+ display: flex;
180
91
  }
181
92
 
182
- :host([padding='sm']) .footer {
183
- padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));
184
- padding-top: 0;
185
- margin-top: var(--dm-spacing-sm, 0.5rem);
93
+ /* Padding variants */
94
+ :host([padding='none']) .card-body {
95
+ padding: 0;
186
96
  }
187
97
 
188
- :host([padding='lg']) .footer {
189
- padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));
190
- padding-top: 0;
191
- margin-top: var(--dm-spacing-lg, 1.5rem);
98
+ :host([padding='lg']) .card-body {
99
+ --card-p: 2rem;
192
100
  }
193
101
 
194
- :host([padding='none']) .footer {
195
- padding: var(--dm-spacing-md, 1rem);
196
- margin-top: 0;
102
+ :host([padding='lg']) .card-header,
103
+ :host([padding='lg']) .card-footer {
104
+ --card-p: 2rem;
197
105
  }
198
106
  `;
199
107
 
@@ -216,8 +124,15 @@ class ElDmCard extends import_el_core.BaseElement {
216
124
  }
217
125
  _handleSlotChange(event) {
218
126
  const slot = event.target;
219
- const slotName = slot.name || "body";
220
- const wrapper = this.shadowRoot.querySelector(`.${slotName}`);
127
+ const slotName = slot.name;
128
+ const wrapperMap = {
129
+ media: "card-image",
130
+ header: "card-header",
131
+ footer: "card-footer",
132
+ "": "card-body"
133
+ };
134
+ const wrapperClass = wrapperMap[slotName] || "card-body";
135
+ const wrapper = this.shadowRoot.querySelector(`.${wrapperClass}`);
221
136
  if (wrapper) {
222
137
  const hasContent = slot.assignedNodes().length > 0;
223
138
  wrapper.classList.toggle("has-content", hasContent);
@@ -236,19 +151,33 @@ class ElDmCard extends import_el_core.BaseElement {
236
151
  });
237
152
  }
238
153
  }
154
+ _getCardClasses() {
155
+ const classes = ["card"];
156
+ if (this.variant && VARIANT_CLASSES[this.variant]) {
157
+ classes.push(VARIANT_CLASSES[this.variant]);
158
+ }
159
+ if (this.interactive) {
160
+ classes.push("card-interactive");
161
+ }
162
+ if (this.padding === "sm") {
163
+ classes.push("card-compact");
164
+ }
165
+ return classes.filter(Boolean).join(" ");
166
+ }
239
167
  render() {
168
+ const cardClasses = this._getCardClasses();
240
169
  return `
241
- <div class="card" part="card">
242
- <div class="media" part="media">
170
+ <div class="${cardClasses}" part="card">
171
+ <div class="card-image" part="media">
243
172
  <slot name="media"></slot>
244
173
  </div>
245
- <div class="header" part="header">
174
+ <div class="card-header" part="header">
246
175
  <slot name="header"></slot>
247
176
  </div>
248
- <div class="body" part="body">
177
+ <div class="card-body" part="body">
249
178
  <slot></slot>
250
179
  </div>
251
- <div class="footer" part="footer">
180
+ <div class="card-footer" part="footer">
252
181
  <slot name="footer"></slot>
253
182
  </div>
254
183
  </div>
@@ -266,5 +195,5 @@ function register() {
266
195
  // src/register.ts
267
196
  register();
268
197
 
269
- //# debugId=1FDA6AFEBD65F6FF64756E2164756E21
198
+ //# debugId=ADCC153F9D3C203F64756E2164756E21
270
199
  //# sourceMappingURL=register.js.map
@@ -2,11 +2,11 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/el-dm-card.ts", "../../src/index.ts", "../../src/register.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * DuskMoon Card Element\n *\n * A container component with header, body, and footer sections.\n *\n * @element el-dm-card\n *\n * @attr {string} variant - Card variant: elevated, outlined, filled\n * @attr {boolean} interactive - Whether the card is clickable/hoverable\n * @attr {string} padding - Padding size: none, sm, md, lg\n *\n * @slot - Default slot for card body content\n * @slot header - Card header content\n * @slot footer - Card footer content\n * @slot media - Media content (image/video) at the top of card\n *\n * @csspart card - The main card container\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n * @csspart media - The media section\n *\n * @fires click - Fired when interactive card is clicked\n *\n * @cssprop --dm-card-padding - Card padding\n * @cssprop --dm-card-border-radius - Border radius\n * @cssprop --dm-card-background - Background color\n * @cssprop --dm-card-border-color - Border color (for outlined variant)\n * @cssprop --dm-card-shadow - Box shadow (for elevated variant)\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\n\n/**\n * Card variant options\n */\nexport type CardVariant = 'elevated' | 'outlined' | 'filled';\n\n/**\n * Card padding options\n */\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nconst styles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n .card {\n display: flex;\n flex-direction: column;\n border-radius: var(--dm-card-border-radius, var(--dm-radius-lg, 0.75rem));\n background-color: var(--dm-card-background, white);\n overflow: hidden;\n transition:\n box-shadow var(--dm-transition-normal, 200ms ease),\n transform var(--dm-transition-normal, 200ms ease);\n }\n\n /* Elevated variant (default) */\n :host(:not([variant])) .card,\n :host([variant='elevated']) .card {\n box-shadow: var(--dm-card-shadow, var(--dm-shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1)));\n }\n\n /* Outlined variant */\n :host([variant='outlined']) .card {\n border: 1px solid var(--dm-card-border-color, var(--dm-gray-200, #e5e7eb));\n box-shadow: none;\n }\n\n /* Filled variant */\n :host([variant='filled']) .card {\n background-color: var(--dm-card-background, var(--dm-gray-50, #f9fafb));\n box-shadow: none;\n }\n\n /* Interactive styles */\n :host([interactive]) .card {\n cursor: pointer;\n }\n\n :host([interactive]) .card:hover {\n transform: translateY(-2px);\n }\n\n :host([interactive][variant='elevated']) .card:hover,\n :host([interactive]:not([variant])) .card:hover {\n box-shadow: var(--dm-shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));\n }\n\n :host([interactive][variant='outlined']) .card:hover {\n border-color: var(--dm-primary, #3b82f6);\n }\n\n :host([interactive][variant='filled']) .card:hover {\n background-color: var(--dm-gray-100, #f3f4f6);\n }\n\n :host([interactive]) .card:focus-visible {\n outline: none;\n box-shadow: var(--dm-focus-ring-offset, 0 0 0 2px white, 0 0 0 4px var(--dm-primary, #3b82f6));\n }\n\n /* Media slot */\n .media {\n display: none;\n }\n\n .media.has-content {\n display: block;\n }\n\n .media ::slotted(*) {\n display: block;\n width: 100%;\n object-fit: cover;\n }\n\n /* Header */\n .header {\n display: none;\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n padding-bottom: 0;\n }\n\n .header.has-content {\n display: block;\n }\n\n /* Body */\n .body {\n flex: 1;\n }\n\n /* Padding variants */\n :host(:not([padding])) .body,\n :host([padding='md']) .body {\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n }\n\n :host([padding='none']) .body {\n padding: 0;\n }\n\n :host([padding='sm']) .body {\n padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));\n }\n\n :host([padding='lg']) .body {\n padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));\n }\n\n :host(:not([padding])) .header,\n :host([padding='md']) .header {\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n padding-bottom: 0;\n }\n\n :host([padding='sm']) .header {\n padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));\n padding-bottom: 0;\n }\n\n :host([padding='lg']) .header {\n padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));\n padding-bottom: 0;\n }\n\n /* Footer */\n .footer {\n display: none;\n padding: var(--dm-card-padding, var(--dm-spacing-md, 1rem));\n padding-top: 0;\n border-top: 1px solid var(--dm-gray-100, #f3f4f6);\n margin-top: var(--dm-spacing-md, 1rem);\n }\n\n .footer.has-content {\n display: block;\n }\n\n :host([padding='sm']) .footer {\n padding: var(--dm-card-padding, var(--dm-spacing-sm, 0.5rem));\n padding-top: 0;\n margin-top: var(--dm-spacing-sm, 0.5rem);\n }\n\n :host([padding='lg']) .footer {\n padding: var(--dm-card-padding, var(--dm-spacing-lg, 1.5rem));\n padding-top: 0;\n margin-top: var(--dm-spacing-lg, 1.5rem);\n }\n\n :host([padding='none']) .footer {\n padding: var(--dm-spacing-md, 1rem);\n margin-top: 0;\n }\n`;\n\nexport class ElDmCard extends BaseElement {\n static properties = {\n variant: { type: String, reflect: true },\n interactive: { type: Boolean, reflect: true },\n padding: { type: String, reflect: true },\n };\n\n /** Card variant */\n declare variant: CardVariant;\n\n /** Whether the card is interactive */\n declare interactive: boolean;\n\n /** Card padding size */\n declare padding: CardPadding;\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n\n // Set up slot change listeners for conditional display\n this.shadowRoot.addEventListener('slotchange', this._handleSlotChange.bind(this));\n\n // Set up click handler for interactive cards\n if (this.interactive) {\n this._setupInteractive();\n }\n }\n\n /**\n * Handle slot content changes\n */\n private _handleSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const slotName = slot.name || 'body';\n const wrapper = this.shadowRoot.querySelector(`.${slotName}`);\n\n if (wrapper) {\n const hasContent = slot.assignedNodes().length > 0;\n wrapper.classList.toggle('has-content', hasContent);\n }\n }\n\n /**\n * Set up interactive card behavior\n */\n private _setupInteractive(): void {\n const card = this.shadowRoot.querySelector('.card') as HTMLElement;\n if (card) {\n card.setAttribute('tabindex', '0');\n card.setAttribute('role', 'button');\n\n card.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.emit('click');\n }\n });\n }\n }\n\n render(): string {\n return `\n <div class=\"card\" part=\"card\">\n <div class=\"media\" part=\"media\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"header\" part=\"header\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"footer\" part=\"footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n `;\n }\n}\n",
5
+ "/**\n * DuskMoon Card Element\n *\n * A container component with header, body, and footer sections.\n * Uses styles from @duskmoon-dev/core for consistent theming.\n *\n * @element el-dm-card\n *\n * @attr {string} variant - Card variant: elevated, outlined, filled\n * @attr {boolean} interactive - Whether the card is clickable/hoverable\n * @attr {string} padding - Padding size: none, sm, md, lg\n *\n * @slot - Default slot for card body content\n * @slot header - Card header content\n * @slot footer - Card footer content\n * @slot media - Media content (image/video) at the top of card\n *\n * @csspart card - The main card container\n * @csspart header - The header section\n * @csspart body - The body section\n * @csspart footer - The footer section\n * @csspart media - The media section\n *\n * @fires click - Fired when interactive card is clicked\n */\n\nimport { BaseElement, css } from '@duskmoon-dev/el-core';\nimport { css as cardCSS } from '@duskmoon-dev/core/components/card';\n\n/**\n * Card variant options\n */\nexport type CardVariant = 'elevated' | 'outlined' | 'filled';\n\n/**\n * Card padding options\n */\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\n// Map of variant attribute values to CSS classes\nconst VARIANT_CLASSES: Record<string, string> = {\n elevated: 'card-elevated',\n outlined: 'card-bordered',\n filled: '', // default card style\n};\n\n// Strip @layer wrapper for Shadow DOM compatibility\nconst coreStyles = cardCSS.replace(/@layer\\s+components\\s*\\{/, '').replace(/\\}\\s*$/, '');\n\nconst styles = css`\n :host {\n display: block;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n\n /* Import core card styles */\n ${coreStyles}\n\n /* Web component specific adjustments */\n\n /* Media slot handling */\n .card-image {\n display: none;\n }\n\n .card-image.has-content {\n display: block;\n }\n\n .card-image ::slotted(*) {\n display: block;\n width: 100%;\n object-fit: cover;\n }\n\n /* Header slot handling */\n .card-header {\n display: none;\n }\n\n .card-header.has-content {\n display: flex;\n }\n\n /* Footer slot handling */\n .card-footer {\n display: none;\n }\n\n .card-footer.has-content {\n display: flex;\n }\n\n /* Padding variants */\n :host([padding='none']) .card-body {\n padding: 0;\n }\n\n :host([padding='lg']) .card-body {\n --card-p: 2rem;\n }\n\n :host([padding='lg']) .card-header,\n :host([padding='lg']) .card-footer {\n --card-p: 2rem;\n }\n`;\n\nexport class ElDmCard extends BaseElement {\n static properties = {\n variant: { type: String, reflect: true },\n interactive: { type: Boolean, reflect: true },\n padding: { type: String, reflect: true },\n };\n\n /** Card variant */\n declare variant: CardVariant;\n\n /** Whether the card is interactive */\n declare interactive: boolean;\n\n /** Card padding size */\n declare padding: CardPadding;\n\n constructor() {\n super();\n this.attachStyles(styles);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n\n // Set up slot change listeners for conditional display\n this.shadowRoot.addEventListener('slotchange', this._handleSlotChange.bind(this));\n\n // Set up click handler for interactive cards\n if (this.interactive) {\n this._setupInteractive();\n }\n }\n\n /**\n * Handle slot content changes\n */\n private _handleSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const slotName = slot.name;\n\n // Map slot names to wrapper class names\n const wrapperMap: Record<string, string> = {\n media: 'card-image',\n header: 'card-header',\n footer: 'card-footer',\n '': 'card-body',\n };\n\n const wrapperClass = wrapperMap[slotName] || 'card-body';\n const wrapper = this.shadowRoot.querySelector(`.${wrapperClass}`);\n\n if (wrapper) {\n const hasContent = slot.assignedNodes().length > 0;\n wrapper.classList.toggle('has-content', hasContent);\n }\n }\n\n /**\n * Set up interactive card behavior\n */\n private _setupInteractive(): void {\n const card = this.shadowRoot.querySelector('.card') as HTMLElement;\n if (card) {\n card.setAttribute('tabindex', '0');\n card.setAttribute('role', 'button');\n\n card.addEventListener('keydown', (event: KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.emit('click');\n }\n });\n }\n }\n\n /**\n * Build CSS class string for the card\n */\n private _getCardClasses(): string {\n const classes = ['card'];\n\n // Add variant class\n if (this.variant && VARIANT_CLASSES[this.variant]) {\n classes.push(VARIANT_CLASSES[this.variant]);\n }\n\n // Add interactive class\n if (this.interactive) {\n classes.push('card-interactive');\n }\n\n // Add compact class for small padding\n if (this.padding === 'sm') {\n classes.push('card-compact');\n }\n\n return classes.filter(Boolean).join(' ');\n }\n\n render(): string {\n const cardClasses = this._getCardClasses();\n\n return `\n <div class=\"${cardClasses}\" part=\"card\">\n <div class=\"card-image\" part=\"media\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-header\" part=\"header\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n `;\n }\n}\n",
6
6
  "/**\n * @duskmoon-dev/el-card\n *\n * DuskMoon Card custom element\n */\n\nimport { ElDmCard } from './el-dm-card.js';\n\nexport { ElDmCard };\nexport type { CardVariant, CardPadding } from './el-dm-card.js';\n\n/**\n * Register the el-dm-card custom element\n *\n * @example\n * ```ts\n * import { register } from '@duskmoon-dev/el-card';\n * register();\n * ```\n */\nexport function register(): void {\n if (!customElements.get('el-dm-card')) {\n customElements.define('el-dm-card', ElDmCard);\n }\n}\n",
7
7
  "/**\n * Auto-register el-dm-card custom element\n *\n * @example\n * ```ts\n * import '@duskmoon-dev/el-card/register';\n *\n * // Now you can use <el-dm-card> in HTML\n * ```\n */\nimport { register } from './index.js';\n\nregister();\n"
8
8
  ],
9
- "mappings": "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",
10
- "debugId": "1FDA6AFEBD65F6FF64756E2164756E21",
9
+ "mappings": "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",
10
+ "debugId": "ADCC153F9D3C203F64756E2164756E21",
11
11
  "names": []
12
12
  }