Skip to content

Commit fbc4f55

Browse files
committed
minor housekeeping
Signed-off-by: Maximilian Inckmann <[email protected]>
1 parent 1effe91 commit fbc4f55

File tree

11 files changed

+485
-145
lines changed

11 files changed

+485
-145
lines changed

packages/react-library/lib/components/stencil-generated/components.server.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export type CopyButtonEvents = NonNullable<unknown>;
4242

4343
export const CopyButton: StencilReactComponent<CopyButtonElement, CopyButtonEvents> = /*@__PURE__*/ createComponent<CopyButtonElement, CopyButtonEvents>({
4444
tagName: 'copy-button',
45-
properties: { value: 'value' },
45+
properties: {
46+
value: 'value',
47+
label: 'label',
48+
},
4649
hydrateModule: import('@kit-data-manager/pid-component/hydrate'),
4750
serializeShadowRoot,
4851
});
@@ -79,7 +82,10 @@ export type PidActionsEvents = NonNullable<unknown>;
7982

8083
export const PidActions: StencilReactComponent<PidActionsElement, PidActionsEvents> = /*@__PURE__*/ createComponent<PidActionsElement, PidActionsEvents>({
8184
tagName: 'pid-actions',
82-
properties: { actions: 'actions' },
85+
properties: {
86+
actions: 'actions',
87+
actionsId: 'actions-id',
88+
},
8389
hydrateModule: import('@kit-data-manager/pid-component/hydrate'),
8490
serializeShadowRoot,
8591
});

packages/stencil-library/src/components.d.ts

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,18 @@ export namespace Components {
1919
"text": string;
2020
}
2121
interface CopyButton {
22-
/**
23-
* The value to copy to the clipboard.
24-
* @type {string}
25-
* @public
26-
*/
27-
"value": string;
22+
/**
23+
* Optional custom label for the button. If not provided, a default label will be used.
24+
* @type {string}
25+
* @public
26+
*/
27+
label?: string;
28+
/**
29+
* The value to copy to the clipboard.
30+
* @type {string}
31+
* @public
32+
*/
33+
value: string;
2834
}
2935
interface JsonViewer {
3036
/**
@@ -71,21 +77,25 @@ export namespace Components {
7177
* @type {string}
7278
* @public
7379
*/
74-
locale: string;
80+
"locale": string;
7581
/**
76-
* Whether to show the flag of the region.
82+
'locale'Whether to show the flag of the region.
7783
* @type {boolean}
7884
* @public
7985
* @default true
8086
*/
81-
showFlag: boolean;
87+
"showFlag": boolean;
8288
}
83-
interface PidActions {
89+
'showFlag'e PidActions {
8490
/**
8591
* Array of actions to display
8692
* @default []
8793
*/
8894
"actions": FoldableAction[];
95+
/**
96+
* Optional ID for the actions container for ARIA references
97+
*/
98+
'actionsId'?: string;
8999
}
90100
/**
91101
* Component for creating collapsible/expandable content sections
@@ -132,72 +142,72 @@ export namespace Components {
132142
* @type {number}
133143
* @default 10
134144
*/
135-
"amo'amountOfItems'mber;
145+
'amountOfItems': number;
136146
/**
137147
* The current level of subcomponents. Defaults to 0. (optional)
138148
* @type {number}
139149
* @default 0
140150
*/
141-
"cur'currentLevelOfSubcomponents'mber;
151+
'currentLevelOfSubcomponents': number;
142152
/**
143153
* Determines the default time to live (TTL) for entries in the IndexedDB. Defaults to 24 hours. Units are in milliseconds. (optional)
144154
* @type {number}
145155
* @default 24 * 60 * 60 * 1000
146156
*/
147-
"def'defaultTTL'mber;
157+
'defaultTTL': number;
148158
/**
149159
* Determines whether components should be emphasized towards their surrounding by border and shadow. If set to true, border and shadows will be shown around the component. It not set, the component won't be surrounded by border and shadow. (optional)
150160
* @type {boolean}
151161
* @default true
152162
*/
153-
"emp'emphasizeComponent'olean;
163+
'emphasizeComponent': boolean;
154164
/**
155165
* Initial height of the component (e.g. '300px', '50vh'). If not set, defaults to 300px.
156166
* @type {string}
157167
*/
158-
"hei'height'tring;
168+
'height'?: string;
159169
/**
160170
* Determines whether subcomponents should generally be shown or not. If set to true, the component won't show any subcomponents. If not set, the component will show subcomponents if the current level of subcomponents is not the total level of subcomponents or greater. (optional)
161171
* @type {boolean}
162172
*/
163-
"hid'hideSubcomponents'olean;
173+
'hideSubcomponents': boolean;
164174
/**
165175
* The total number of levels of subcomponents to show. Defaults to 1. (optional)
166176
* @type {number}
167177
* @default 1
168178
*/
169-
"lev'levelOfSubcomponents'mber;
179+
'levelOfSubcomponents': number;
170180
/**
171181
* Determines whether the component is open or not by default. (optional)
172182
* @type {boolean}
173183
*/
174-
"ope'openByDefault'olean;
184+
'openByDefault': boolean;
175185
/**
176186
* A stringified JSON object containing settings for this component. The resulting object is passed to every subcomponent, so that every component has the same settings. Values and the according type are defined by the components themselves. (optional) Schema: ```typescript { type: string, values: { name: string, value: any }[] }[] ```
177187
* @type {string}
178188
* @default '[]'
179189
*/
180-
"set'settings'ring;
190+
'settings': string;
181191
/**
182192
* Determines whether on the top level the copy button is shown. If set to true, the copy button is shown also on the top level. It not set, the copy button is only shown for sub-components. (optional)
183193
* @type {boolean}
184194
* @default true
185195
*/
186-
"sho'showTopLevelCopy'olean;
196+
'showTopLevelCopy': boolean;
187197
/**
188198
* Updates the component sizing and styling based on the expanded state This method is now handled by the pid-collapsible component
189199
*/
190-
"upd'updateComponentSizing' => Promise<void>;
200+
'updateComponentSizing': () => Promise<void>;
191201
/**
192202
* The value to parse, evaluate and render.
193203
* @type {string}
194204
*/
195-
"val'value'ring;
205+
'value': string;
196206
/**
197207
* Initial width of the component (e.g. '500px', '50%'). If not set, defaults to 500px on large screens, 400px on medium screens, and 300px on small screens.
198208
* @type {string}
199209
*/
200-
"wid'width'tring;
210+
'width'?: string;
201211
}
202212

203213
interface PidDataTable {
@@ -456,6 +466,12 @@ declare namespace LocalJSX {
456466
}
457467
interface CopyButton {
458468
/**
469+
* Optional custom label for the button. If not provided, a default label will be used.
470+
* @type {string}
471+
* @public
472+
*/
473+
'label'?: string;
474+
/**
459475
* The value to copy to the clipboard.
460476
* @type {string}
461477
* @public
@@ -514,6 +530,10 @@ declare namespace LocalJSX {
514530
* @default []
515531
*/
516532
"actions"?: FoldableAction[];
533+
/**
534+
* Optional ID for the actions container for ARIA references
535+
*/
536+
'actionsId'?: string;
517537
}
518538
/**
519539
* Component for creating collapsible/expandable content sections

packages/stencil-library/src/components/copy-button/copy-button.tsx

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,22 @@ export class CopyButton {
99
* Internal state to track if copy was successful
1010
*/
1111
@State() copied: boolean = false;
12+
1213
/**
1314
* The value to copy to the clipboard.
1415
* @type {string}
1516
* @public
1617
*/
1718
@Prop() value!: string;
1819

20+
/**
21+
* Optional custom label for the button.
22+
* If not provided, a default label will be used.
23+
* @type {string}
24+
* @public
25+
*/
26+
@Prop() label?: string;
27+
1928
/**
2029
* Copies the given value to the clipboard and updates the state to show success message.
2130
*/
@@ -24,18 +33,14 @@ export class CopyButton {
2433
event.stopPropagation();
2534
event.preventDefault();
2635

27-
console.log('Copying value:', this.value);
28-
2936
try {
3037
// Try the Async Clipboard API first
3138
if ('clipboard' in navigator) {
3239
try {
3340
await navigator.clipboard.writeText(this.value);
34-
console.debug('Copied to clipboard using Async Clipboard API:', this.value);
3541
this.showSuccess();
3642
return;
3743
} catch (err) {
38-
console.error('Async Clipboard API failed, falling back to execCommand:', err);
3944
// Fall through to execCommand fallback
4045
}
4146
}
@@ -44,7 +49,10 @@ export class CopyButton {
4449
const textArea = document.createElement('textarea');
4550
textArea.value = this.value;
4651

47-
// Add to DOM with Tailwind classes for positioning
52+
// Add accessibility attributes and Tailwind classes for positioning
53+
textArea.setAttribute('aria-hidden', 'true');
54+
textArea.setAttribute('tabindex', '-1');
55+
textArea.setAttribute('readonly', 'readonly');
4856
textArea.className = 'fixed top-0 left-0 opacity-0 pointer-events-none z-[9999] w-[10em] h-[10em]';
4957

5058
document.body.appendChild(textArea);
@@ -57,7 +65,6 @@ export class CopyButton {
5765

5866
try {
5967
const success = document.execCommand('copy');
60-
console.log(`execCommand copy was ${success ? 'successful' : 'unsuccessful'}.`);
6168
if (success) {
6269
this.showSuccess();
6370
} else {
@@ -71,20 +78,19 @@ export class CopyButton {
7178
textArea.setSelectionRange(0, textArea.value.length); // For mobile devices
7279

7380
const secondAttempt = document.execCommand('copy');
74-
console.log(`Second attempt execCommand copy was ${secondAttempt ? 'successful' : 'unsuccessful'}.`);
7581
if (secondAttempt) {
7682
this.showSuccess();
7783
}
7884
}
7985
}
8086
} catch (err) {
81-
console.error('Failed to copy text with execCommand:', err);
87+
// Error handling is silent to not disrupt user experience
8288
} finally {
8389
document.body.removeChild(textArea);
8490
}
8591
}, 200); // Increased timeout for better reliability
8692
} catch (err) {
87-
console.error('Failed to copy text:', err);
93+
// Error handling is silent to not disrupt user experience
8894
}
8995
};
9096

@@ -100,16 +106,43 @@ export class CopyButton {
100106
}, 1500);
101107
}
102108

109+
/**
110+
* Get the appropriate aria-label based on component state and props
111+
*/
112+
private getAriaLabel(): string {
113+
const baseLabel = this.label || 'content';
114+
return this.copied ? `${baseLabel} copied to clipboard` : `Copy ${baseLabel} to clipboard`;
115+
}
116+
103117
render() {
118+
// Determine button text based on state
119+
const buttonText = this.copied ? '✓ Copied!' : 'Copy';
120+
121+
// Get appropriate aria-label
122+
const ariaLabel = this.getAriaLabel();
123+
104124
return (
105125
<Host class={'inline-block align-baseline text-xs'}>
126+
{/* Hidden live region for screen readers */}
127+
{this.copied && (
128+
<span class="sr-only" aria-live="assertive">
129+
Content copied to clipboard
130+
</span>
131+
)}
132+
106133
<button
107-
class={`${this.copied ? 'bg-green-200' : 'bg-white hover:bg-blue-200'} border border-slate-500 text-slate-800 font-medium font-mono rounded-md px-2 py-0.5 hover:text-slate-900 flex-none max-h-min items-center z-30 relative`}
134+
class={`${this.copied ? 'bg-green-200' : 'bg-white hover:bg-blue-200'}
135+
border border-slate-500 text-slate-800 font-medium font-mono
136+
rounded-md px-2 py-0.5 hover:text-slate-900 flex-none max-h-min
137+
items-center z-30 relative
138+
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1
139+
transition-colors duration-200`}
108140
onClick={e => this.copyValue(e)}
109-
aria-label={this.copied ? 'Copied to clipboard' : 'Copy to clipboard'}
141+
aria-label={ariaLabel}
142+
title={ariaLabel}
110143
type="button"
111144
>
112-
{this.copied ? '✓ Copied!' : 'Copy'}
145+
{buttonText}
113146
</button>
114147
</Host>
115148
);

packages/stencil-library/src/components/copy-button/readme.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
## Properties
77

8-
| Property | Attribute | Description | Type | Default |
9-
| -------------------- | --------- | ----------------------------------- | -------- | ----------- |
10-
| `value` _(required)_ | `value` | The value to copy to the clipboard. | `string` | `undefined` |
8+
| Property | Attribute | Description | Type | Default |
9+
|----------------------|-----------|--------------------------------------------------------------------------------------|----------|-------------|
10+
| `label` | `label` | Optional custom label for the button. If not provided, a default label will be used. | `string` | `undefined` |
11+
| `value` _(required)_ | `value` | The value to copy to the clipboard. | `string` | `undefined` |
1112

1213

1314
## Dependencies

0 commit comments

Comments
 (0)