@dile/ui 2.18.2 → 2.18.3

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,143 @@
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
+ <a
51
+ href="#"
52
+ role="button"
53
+ tabindex="0"
54
+ @click="${this.handleCopy}"
55
+ @keydown="${this.handleKeydown}"
56
+ >
57
+ <slot></slot>
58
+ </a>
59
+ <dile-floating-feedback
60
+ id="copy-feedback"
61
+ feedback="${this.feedbackText}"
62
+ duration="${this.copiedDuration}"
63
+ ?hideIcon=${this.hideIcon}
64
+ .icon=${contentCopyIcon}
65
+ ></dile-floating-feedback>
66
+ `;
67
+ }
68
+
69
+ handleCopy(e) {
70
+ e.preventDefault();
71
+ this.copyToClipboard();
72
+ }
73
+
74
+ handleKeydown(e) {
75
+ if (e.key === 'Enter' || e.key === ' ') {
76
+ e.preventDefault();
77
+ this.copyToClipboard();
78
+ }
79
+ }
80
+
81
+ async copyToClipboard() {
82
+ try {
83
+ // Try to use Clipboard API first (modern browsers)
84
+ if (navigator.clipboard && navigator.clipboard.writeText) {
85
+ await navigator.clipboard.writeText(this.copy);
86
+ } else {
87
+ // Fallback for older browsers
88
+ this.copyWithExecCommand();
89
+ }
90
+
91
+ // Dispatch custom event
92
+ this.dispatchEvent(
93
+ new CustomEvent('dile-text-copied', {
94
+ detail: { text: this.copy },
95
+ bubbles: true,
96
+ composed: true
97
+ })
98
+ );
99
+
100
+ // Show visual feedback
101
+ this.showCopiedFeedback();
102
+ } catch (error) {
103
+ console.error('Failed to copy text:', error);
104
+ // Try fallback if Clipboard API fails
105
+ try {
106
+ this.copyWithExecCommand();
107
+ this.dispatchEvent(
108
+ new CustomEvent('dile-text-copied', {
109
+ detail: { text: this.copy },
110
+ bubbles: true,
111
+ composed: true
112
+ })
113
+ );
114
+ this.showCopiedFeedback();
115
+ } catch (fallbackError) {
116
+ console.error('Fallback copy method also failed:', fallbackError);
117
+ }
118
+ }
119
+ }
120
+
121
+ copyWithExecCommand() {
122
+ const textArea = document.createElement('textarea');
123
+ textArea.value = this.copy;
124
+ textArea.style.position = 'fixed';
125
+ textArea.style.left = '-999999px';
126
+ textArea.style.top = '-999999px';
127
+ document.body.appendChild(textArea);
128
+ textArea.focus();
129
+ textArea.select();
130
+ const successful = document.execCommand('copy');
131
+ document.body.removeChild(textArea);
132
+ if (!successful) {
133
+ throw new Error('execCommand copy failed');
134
+ }
135
+ }
136
+
137
+ showCopiedFeedback() {
138
+ const feedback = this.shadowRoot.querySelector('#copy-feedback');
139
+ if (feedback) {
140
+ feedback.show();
141
+ }
142
+ }
143
+ }
@@ -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,196 @@
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
+ <div class="feedback-anchor"></div>
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 this component
120
+ const rect = this.getBoundingClientRect();
121
+ const x = rect.left + rect.width / 2;
122
+ const y = rect.top;
123
+
124
+ floatingElement.style.left = (x - 50) + 'px'; // Center roughly
125
+ floatingElement.style.top = y + 'px';
126
+
127
+ // Add animation keyframes to document if not already present
128
+ this.ensureAnimationStyles();
129
+
130
+ // Add to document body
131
+ document.body.appendChild(floatingElement);
132
+
133
+ // Remove element after animation completes
134
+ const totalTime = this.duration + delay;
135
+ setTimeout(() => {
136
+ floatingElement.remove();
137
+ this.activeInstances.delete(instanceId);
138
+ }, totalTime);
139
+ }
140
+
141
+ ensureAnimationStyles() {
142
+ // Check if styles are already injected
143
+ if (document.getElementById('dile-floating-feedback-styles')) {
144
+ return;
145
+ }
146
+
147
+ const styleElement = document.createElement('style');
148
+ styleElement.id = 'dile-floating-feedback-styles';
149
+ styleElement.textContent = `
150
+ @keyframes dile-floating-feedback-animation {
151
+ 0% {
152
+ opacity: 0;
153
+ transform: translateY(0) scale(0.8);
154
+ }
155
+ 50% {
156
+ opacity: 1;
157
+ transform: translateY(-15px) scale(1);
158
+ }
159
+ 100% {
160
+ opacity: 0;
161
+ transform: translateY(-30px) scale(1);
162
+ }
163
+ }
164
+
165
+ @media (prefers-reduced-motion: reduce) {
166
+ @keyframes dile-floating-feedback-animation {
167
+ 0% {
168
+ opacity: 0;
169
+ transform: translateY(0);
170
+ }
171
+ 50% {
172
+ opacity: 1;
173
+ transform: translateY(0);
174
+ }
175
+ 100% {
176
+ opacity: 0;
177
+ transform: translateY(0);
178
+ }
179
+ }
180
+ }
181
+
182
+ .dile-floating-feedback-text {
183
+ --dile-floating-feedback-duration: 1000ms;
184
+ --dile-floating-feedback-font-size: 0.875rem;
185
+ --dile-floating-feedback-font-weight: 500;
186
+ --dile-floating-feedback-color: #fff;
187
+ --dile-floating-feedback-background-color: rgba(0, 0, 0, 0.8);
188
+ --dile-floating-feedback-padding: 0.5rem 0.75rem;
189
+ --dile-floating-feedback-border-radius: 4px;
190
+ --dile-floating-feedback-translate-y: 30px;
191
+ }
192
+ `;
193
+
194
+ document.head.appendChild(styleElement);
195
+ }
196
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/ui",
3
- "version": "2.18.2",
3
+ "version": "2.18.3",
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": "5a5d851418d9a02f6cf24e937005ee9361085678"
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;