@dile/ui 2.18.2 → 2.19.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.
@@ -0,0 +1,3 @@
1
+ import { DileCopyText } from "./index.js";
2
+
3
+ export { DileCopyText };
@@ -0,0 +1,5 @@
1
+ import { DileCopyText } from './src/DileCopyText.js';
2
+
3
+ window.customElements.define('dile-copy-text', DileCopyText);
4
+
5
+ export { DileCopyText };
@@ -0,0 +1,144 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import { contentCopyIcon } from '@dile/icons';
3
+ import '../../floating-feedback/floating-feedback.js';
4
+
5
+ export class DileCopyText extends LitElement {
6
+ static styles = [
7
+ css`
8
+ :host {
9
+ display: inline-block;
10
+ }
11
+
12
+ a {
13
+ cursor: pointer;
14
+ text-decoration: var(--dile-copy-text-text-decoration, none);
15
+ color: var(--dile-copy-text-color, inherit);
16
+ transition: all var(--dile-copy-text-transition-duration, 0.3s) ease;
17
+ }
18
+
19
+ a:hover {
20
+ color: var(--dile-copy-text-hover-color, #0066cc);
21
+ text-decoration: var(--dile-copy-text-hover-text-decoration, underline);
22
+ }
23
+
24
+ a:focus {
25
+ outline: var(--dile-copy-text-focus-outline, 2px solid #0066cc);
26
+ outline-offset: 2px;
27
+ }
28
+ `
29
+ ];
30
+
31
+ static get properties() {
32
+ return {
33
+ copy: { type: String },
34
+ copiedDuration: { type: Number },
35
+ feedbackText: { type: String },
36
+ hideIcon: { type: Boolean }
37
+ };
38
+ }
39
+
40
+ constructor() {
41
+ super();
42
+ this.copy = '';
43
+ this.copiedDuration = 1000; // 2 seconds by default
44
+ this.feedbackText = 'Copied!';
45
+ this.hideIcon = false;
46
+ }
47
+
48
+ render() {
49
+ return html`
50
+ <dile-floating-feedback
51
+ id="copy-feedback"
52
+ feedback="${this.feedbackText}"
53
+ duration="${this.copiedDuration}"
54
+ ?hideIcon=${this.hideIcon}
55
+ .icon=${contentCopyIcon}
56
+ >
57
+ <a
58
+ href="#"
59
+ role="button"
60
+ tabindex="0"
61
+ @click="${this.handleCopy}"
62
+ @keydown="${this.handleKeydown}"
63
+ >
64
+ <slot></slot>
65
+ </a>
66
+ </dile-floating-feedback>
67
+ `;
68
+ }
69
+
70
+ handleCopy(e) {
71
+ e.preventDefault();
72
+ this.copyToClipboard();
73
+ }
74
+
75
+ handleKeydown(e) {
76
+ if (e.key === 'Enter' || e.key === ' ') {
77
+ e.preventDefault();
78
+ this.copyToClipboard();
79
+ }
80
+ }
81
+
82
+ async copyToClipboard() {
83
+ try {
84
+ // Try to use Clipboard API first (modern browsers)
85
+ if (navigator.clipboard && navigator.clipboard.writeText) {
86
+ await navigator.clipboard.writeText(this.copy);
87
+ } else {
88
+ // Fallback for older browsers
89
+ this.copyWithExecCommand();
90
+ }
91
+
92
+ // Dispatch custom event
93
+ this.dispatchEvent(
94
+ new CustomEvent('dile-text-copied', {
95
+ detail: { text: this.copy },
96
+ bubbles: true,
97
+ composed: true
98
+ })
99
+ );
100
+
101
+ // Show visual feedback
102
+ this.showCopiedFeedback();
103
+ } catch (error) {
104
+ console.error('Failed to copy text:', error);
105
+ // Try fallback if Clipboard API fails
106
+ try {
107
+ this.copyWithExecCommand();
108
+ this.dispatchEvent(
109
+ new CustomEvent('dile-text-copied', {
110
+ detail: { text: this.copy },
111
+ bubbles: true,
112
+ composed: true
113
+ })
114
+ );
115
+ this.showCopiedFeedback();
116
+ } catch (fallbackError) {
117
+ console.error('Fallback copy method also failed:', fallbackError);
118
+ }
119
+ }
120
+ }
121
+
122
+ copyWithExecCommand() {
123
+ const textArea = document.createElement('textarea');
124
+ textArea.value = this.copy;
125
+ textArea.style.position = 'fixed';
126
+ textArea.style.left = '-999999px';
127
+ textArea.style.top = '-999999px';
128
+ document.body.appendChild(textArea);
129
+ textArea.focus();
130
+ textArea.select();
131
+ const successful = document.execCommand('copy');
132
+ document.body.removeChild(textArea);
133
+ if (!successful) {
134
+ throw new Error('execCommand copy failed');
135
+ }
136
+ }
137
+
138
+ showCopiedFeedback() {
139
+ const feedback = this.shadowRoot.querySelector('#copy-feedback');
140
+ if (feedback) {
141
+ feedback.show();
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,3 @@
1
+ import { DileFloatingFeedback } from "./index.js";
2
+
3
+ export { DileFloatingFeedback };
@@ -0,0 +1,5 @@
1
+ import { DileFloatingFeedback } from './src/DileFloatingFeedback.js';
2
+
3
+ window.customElements.define('dile-floating-feedback', DileFloatingFeedback);
4
+
5
+ export { DileFloatingFeedback };
@@ -0,0 +1,203 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import '../../icon/icon.js';
3
+
4
+ export class DileFloatingFeedback extends LitElement {
5
+ static styles = [
6
+ css`
7
+ :host {
8
+ display: inline-block;
9
+ position: relative;
10
+ }
11
+
12
+ .feedback-anchor {
13
+ display: inline-block;
14
+ }
15
+ `
16
+ ];
17
+
18
+ static get properties() {
19
+ return {
20
+ feedback: { type: String },
21
+ duration: { type: Number },
22
+ icon: { type: Object },
23
+ hideIcon: { type: Boolean }
24
+ };
25
+ }
26
+
27
+ constructor() {
28
+ super();
29
+ this.feedback = '';
30
+ this.duration = 1000;
31
+ this.icon = null;
32
+ this.hideIcon = false;
33
+ this.activeInstances = new Set();
34
+ }
35
+
36
+ render() {
37
+ return html`
38
+ <slot class="feedback-anchor"></slot>
39
+ `;
40
+ }
41
+
42
+ show(text) {
43
+ const feedbackText = text || this.feedback;
44
+ if (!feedbackText) {
45
+ console.warn('dile-floating-feedback: No text provided');
46
+ return;
47
+ }
48
+
49
+ this.createFloatingElement(feedbackText);
50
+ }
51
+
52
+ createFloatingElement(text) {
53
+ // Create instance ID and add to active set
54
+ const instanceId = Math.random();
55
+ this.activeInstances.add(instanceId);
56
+
57
+ // Calculate delay based on number of active instances
58
+ const delay = (this.activeInstances.size - 1) * 50;
59
+
60
+ // Create the floating element
61
+ const floatingElement = document.createElement('div');
62
+ floatingElement.className = 'dile-floating-feedback-text';
63
+
64
+ // Get computed CSS variables from the component
65
+ const computedStyle = window.getComputedStyle(this);
66
+ const bgColor = computedStyle.getPropertyValue('--dile-floating-feedback-background-color').trim() || 'rgba(0, 0, 0, 0.8)';
67
+ const textColor = computedStyle.getPropertyValue('--dile-floating-feedback-text-color').trim() || '#fff';
68
+ const fontSize = computedStyle.getPropertyValue('--dile-floating-feedback-font-size').trim() || '0.875rem';
69
+ const fontWeight = computedStyle.getPropertyValue('--dile-floating-feedback-font-weight').trim() || '500';
70
+ const padding = computedStyle.getPropertyValue('--dile-floating-feedback-padding').trim() || '0.5rem 0.75rem';
71
+ const borderRadius = computedStyle.getPropertyValue('--dile-floating-feedback-border-radius').trim() || '4px';
72
+
73
+ // Style the floating element with computed values
74
+ Object.assign(floatingElement.style, {
75
+ position: 'fixed',
76
+ pointerEvents: 'none',
77
+ zIndex: '10000',
78
+ fontFamily: 'inherit',
79
+ fontSize: fontSize,
80
+ fontWeight: fontWeight,
81
+ backgroundColor: bgColor,
82
+ color: textColor,
83
+ padding: padding,
84
+ borderRadius: borderRadius,
85
+ animation: `dile-floating-feedback-animation ${this.duration}ms ease-out forwards`,
86
+ animationDelay: delay + 'ms'
87
+ });
88
+
89
+ // Create content container (flexbox if there's an icon)
90
+ const contentContainer = document.createElement('div');
91
+ if (!this.hideIcon && this.icon) {
92
+ Object.assign(contentContainer.style, {
93
+ display: 'flex',
94
+ alignItems: 'center',
95
+ gap: '0.5rem',
96
+ whiteSpace: 'nowrap'
97
+ });
98
+
99
+ // Create and add icon element
100
+ const iconElement = document.createElement('dile-icon');
101
+ iconElement.icon = this.icon;
102
+ iconElement.style.setProperty('--dile-icon-size', 'var(--dile-floating-feedback-icon-size, 1.2em)');
103
+ iconElement.style.setProperty('--dile-icon-color', textColor);
104
+ contentContainer.appendChild(iconElement);
105
+ } else {
106
+ Object.assign(contentContainer.style, {
107
+ whiteSpace: 'nowrap'
108
+ });
109
+ }
110
+
111
+ // Create and add text element
112
+ const textSpan = document.createElement('span');
113
+ textSpan.textContent = text;
114
+ contentContainer.appendChild(textSpan);
115
+
116
+ // Add content container to floating element
117
+ floatingElement.appendChild(contentContainer);
118
+
119
+ // Calculate position relative to the slot's content
120
+ const anchorElement = this.children[0];
121
+ if (!anchorElement) {
122
+ console.warn('dile-floating-feedback: No element in slot to anchor to');
123
+ floatingElement.remove();
124
+ return;
125
+ }
126
+
127
+ const rect = anchorElement.getBoundingClientRect();
128
+ const x = rect.left + rect.width / 2;
129
+ const y = rect.top;
130
+
131
+ floatingElement.style.left = (x - 50) + 'px'; // Center roughly
132
+ floatingElement.style.top = y + 'px';
133
+
134
+ // Add animation keyframes to document if not already present
135
+ this.ensureAnimationStyles();
136
+
137
+ // Add to document body
138
+ document.body.appendChild(floatingElement);
139
+
140
+ // Remove element after animation completes
141
+ const totalTime = this.duration + delay;
142
+ setTimeout(() => {
143
+ floatingElement.remove();
144
+ this.activeInstances.delete(instanceId);
145
+ }, totalTime);
146
+ }
147
+
148
+ ensureAnimationStyles() {
149
+ // Check if styles are already injected
150
+ if (document.getElementById('dile-floating-feedback-styles')) {
151
+ return;
152
+ }
153
+
154
+ const styleElement = document.createElement('style');
155
+ styleElement.id = 'dile-floating-feedback-styles';
156
+ styleElement.textContent = `
157
+ @keyframes dile-floating-feedback-animation {
158
+ 0% {
159
+ opacity: 0;
160
+ transform: translateY(0) scale(0.8);
161
+ }
162
+ 50% {
163
+ opacity: 1;
164
+ transform: translateY(-15px) scale(1);
165
+ }
166
+ 100% {
167
+ opacity: 0;
168
+ transform: translateY(-30px) scale(1);
169
+ }
170
+ }
171
+
172
+ @media (prefers-reduced-motion: reduce) {
173
+ @keyframes dile-floating-feedback-animation {
174
+ 0% {
175
+ opacity: 0;
176
+ transform: translateY(0);
177
+ }
178
+ 50% {
179
+ opacity: 1;
180
+ transform: translateY(0);
181
+ }
182
+ 100% {
183
+ opacity: 0;
184
+ transform: translateY(0);
185
+ }
186
+ }
187
+ }
188
+
189
+ .dile-floating-feedback-text {
190
+ --dile-floating-feedback-duration: 1000ms;
191
+ --dile-floating-feedback-font-size: 0.875rem;
192
+ --dile-floating-feedback-font-weight: 500;
193
+ --dile-floating-feedback-color: #fff;
194
+ --dile-floating-feedback-background-color: rgba(0, 0, 0, 0.8);
195
+ --dile-floating-feedback-padding: 0.5rem 0.75rem;
196
+ --dile-floating-feedback-border-radius: 4px;
197
+ --dile-floating-feedback-translate-y: 30px;
198
+ }
199
+ `;
200
+
201
+ document.head.appendChild(styleElement);
202
+ }
203
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/ui",
3
- "version": "2.18.2",
3
+ "version": "2.19.0",
4
4
  "description": "UI Core components from dile-components.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "homepage": "https://dile-components.com/",
22
22
  "dependencies": {
23
- "@dile/icons": "^2.4.2",
23
+ "@dile/icons": "^2.4.3",
24
24
  "lit": "^2.7.0 || ^3.0.0"
25
25
  },
26
26
  "publishConfig": {
27
27
  "access": "public"
28
28
  },
29
- "gitHead": "2e660d50208c7a456bc593220121cad7f2885f9c"
29
+ "gitHead": "b66783df8f27b601e24de791acde3451d93dfe07"
30
30
  }
package/styles/colors.css CHANGED
@@ -24,7 +24,7 @@
24
24
  --dile-on-primary-light-color: #303030;
25
25
  --dile-primary-dark-color: #d7d353;
26
26
  --dile-on-primary-dark-color: #303030;
27
- --dile-secondary-light-color: #beed8e;
27
+ --dile-secondary-light-color: #d2f6ae;
28
28
  --dile-on-secondary-light-color: #303030;
29
29
  --dile-secondary-dark-color: #43842e;
30
30
  --dile-on-secondary-dark-color: #ffffff;