@uibit/scratch-reveal 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 UIBit Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Scratch Reveal
2
+
3
+ [Interactive Demonstration](https://rawlings.github.io/uibit/components/scratch-reveal)
4
+
5
+ Scratch Reveal is an interactive promotional display component that mimics a physical scratch-card interaction. By obscuring content (such as a discount code, coupon, or image) with an erasable overlay, it introduces gamification and anticipation to user actions.
6
+
7
+ ## Value Delivery
8
+
9
+ - **Gamified Engagement** – Adds interactive play to digital interfaces, encouraging longer user session times.
10
+ - **Anticipation & Discovery** – Creates a memorable experience by delaying the gratification of the final reward.
11
+ - **Conversion Driver** – Ideal for revealing exclusive discount codes, mystery deals, and rewards in campaign flows.
12
+ - **Cross-Platform Compatibility** – Offers a responsive scratching canvas that translates touch swipes on mobile and mouse gestures on desktop.
13
+
14
+ ## Ideal Applications
15
+
16
+ - **E-Commerce Promotions** – Revealing surprise sales, seasonal offers, and coupon codes.
17
+ - **Loyalty Programs** – Gamifying reward distributions and membership perks.
18
+ - **Brand Campaigns** – Unveiling secret announcements or hidden content.
19
+
20
+ ## Further Information
21
+
22
+ Detailed design guidelines, customizable attributes, and integration examples are available on our documentation site.
23
+
24
+
25
+ ## Changelog
26
+
27
+ Please see the [Changelog](CHANGELOG.md) for version history.
@@ -0,0 +1,324 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "readme": "",
4
+ "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "src/index.ts",
8
+ "declarations": [],
9
+ "exports": [
10
+ {
11
+ "kind": "js",
12
+ "name": "ScratchReveal",
13
+ "declaration": {
14
+ "name": "ScratchReveal",
15
+ "module": "./scratch-reveal"
16
+ }
17
+ },
18
+ {
19
+ "kind": "js",
20
+ "name": "*",
21
+ "declaration": {
22
+ "name": "*",
23
+ "module": "src/types"
24
+ }
25
+ }
26
+ ]
27
+ },
28
+ {
29
+ "kind": "javascript-module",
30
+ "path": "src/scratch-reveal.ts",
31
+ "declarations": [
32
+ {
33
+ "kind": "class",
34
+ "description": "Canvas-based scratch card that reveals slotted content as the user\nscratches over a configurable overlay layer.",
35
+ "name": "ScratchReveal",
36
+ "cssProperties": [
37
+ {
38
+ "description": "Width of the scratch card",
39
+ "name": "--uibit-scratch-reveal-width",
40
+ "default": "25rem"
41
+ },
42
+ {
43
+ "description": "Height of the scratch card",
44
+ "name": "--uibit-scratch-reveal-height",
45
+ "default": "12.5rem"
46
+ },
47
+ {
48
+ "description": "Border radius of the card",
49
+ "name": "--uibit-scratch-reveal-border-radius",
50
+ "default": "0.5rem"
51
+ },
52
+ {
53
+ "description": "Background color of the revealed content area",
54
+ "name": "--uibit-scratch-reveal-background",
55
+ "default": "#f3f4f6"
56
+ },
57
+ {
58
+ "description": "Padding of the revealed content area",
59
+ "name": "--uibit-scratch-reveal-padding",
60
+ "default": "1rem"
61
+ },
62
+ {
63
+ "description": "Font size of the revealed content",
64
+ "name": "--uibit-scratch-reveal-font-size",
65
+ "default": "1rem"
66
+ },
67
+ {
68
+ "description": "Font weight of the revealed content",
69
+ "name": "--uibit-scratch-reveal-font-weight",
70
+ "default": "600"
71
+ },
72
+ {
73
+ "description": "Text color of the revealed content",
74
+ "name": "--uibit-scratch-reveal-color",
75
+ "default": "#111827"
76
+ },
77
+ {
78
+ "description": "Fill color of the scratchable overlay",
79
+ "name": "--uibit-scratch-reveal-overlay-color",
80
+ "default": "#d1d5db"
81
+ },
82
+ {
83
+ "description": "Color of the scratch instruction hint",
84
+ "name": "--uibit-scratch-reveal-instructions-color",
85
+ "default": "rgba(0,0,0,0.4)"
86
+ },
87
+ {
88
+ "description": "Font size of the scratch instruction hint",
89
+ "name": "--uibit-scratch-reveal-instructions-font-size",
90
+ "default": "0.875rem"
91
+ }
92
+ ],
93
+ "slots": [
94
+ {
95
+ "description": "The content revealed beneath the scratch overlay",
96
+ "name": ""
97
+ }
98
+ ],
99
+ "members": [
100
+ {
101
+ "kind": "field",
102
+ "name": "revealThreshold",
103
+ "type": {
104
+ "text": "number"
105
+ },
106
+ "default": "50",
107
+ "description": "Percentage (0–100) of the overlay that must be scratched before the `scratch-reveal` event fires.",
108
+ "attribute": "reveal-threshold"
109
+ },
110
+ {
111
+ "kind": "field",
112
+ "name": "_scratchProgress",
113
+ "type": {
114
+ "text": "number"
115
+ },
116
+ "privacy": "private",
117
+ "default": "0"
118
+ },
119
+ {
120
+ "kind": "field",
121
+ "name": "brushSize",
122
+ "type": {
123
+ "text": "number"
124
+ },
125
+ "readonly": true
126
+ },
127
+ {
128
+ "kind": "field",
129
+ "name": "isRevealed",
130
+ "type": {
131
+ "text": "boolean"
132
+ },
133
+ "privacy": "private",
134
+ "default": "false"
135
+ },
136
+ {
137
+ "kind": "field",
138
+ "name": "showInstructions",
139
+ "type": {
140
+ "text": "boolean"
141
+ },
142
+ "privacy": "private",
143
+ "default": "true"
144
+ },
145
+ {
146
+ "kind": "field",
147
+ "name": "canvas",
148
+ "type": {
149
+ "text": "HTMLCanvasElement | undefined"
150
+ },
151
+ "privacy": "private"
152
+ },
153
+ {
154
+ "kind": "field",
155
+ "name": "ctx",
156
+ "type": {
157
+ "text": "CanvasRenderingContext2D | null | undefined"
158
+ },
159
+ "privacy": "private"
160
+ },
161
+ {
162
+ "kind": "field",
163
+ "name": "isDrawing",
164
+ "type": {
165
+ "text": "boolean"
166
+ },
167
+ "privacy": "private",
168
+ "default": "false"
169
+ },
170
+ {
171
+ "kind": "field",
172
+ "name": "_rafId",
173
+ "type": {
174
+ "text": "number | undefined"
175
+ },
176
+ "privacy": "private"
177
+ },
178
+ {
179
+ "kind": "method",
180
+ "name": "setupCanvas",
181
+ "privacy": "private"
182
+ },
183
+ {
184
+ "kind": "method",
185
+ "name": "drawOverlay",
186
+ "privacy": "private"
187
+ },
188
+ {
189
+ "kind": "method",
190
+ "name": "attachEventListeners",
191
+ "privacy": "private"
192
+ },
193
+ {
194
+ "kind": "method",
195
+ "name": "startScratching",
196
+ "privacy": "private",
197
+ "parameters": [
198
+ {
199
+ "name": "e",
200
+ "type": {
201
+ "text": "MouseEvent"
202
+ }
203
+ }
204
+ ]
205
+ },
206
+ {
207
+ "kind": "method",
208
+ "name": "stopScratching",
209
+ "privacy": "private"
210
+ },
211
+ {
212
+ "kind": "method",
213
+ "name": "scratch",
214
+ "privacy": "private",
215
+ "parameters": [
216
+ {
217
+ "name": "e",
218
+ "type": {
219
+ "text": "MouseEvent | Touch"
220
+ }
221
+ }
222
+ ]
223
+ },
224
+ {
225
+ "kind": "method",
226
+ "name": "calculateRevealPercentage",
227
+ "privacy": "private"
228
+ },
229
+ {
230
+ "kind": "method",
231
+ "name": "reset"
232
+ }
233
+ ],
234
+ "events": [
235
+ {
236
+ "type": {
237
+ "text": "{ percentage: number }"
238
+ },
239
+ "description": "Fired as the user scratches; `detail.percentage` is 0–100",
240
+ "name": "scratch-progress"
241
+ },
242
+ {
243
+ "type": {
244
+ "text": "{ percentage: number }"
245
+ },
246
+ "description": "Fired once when the revealed area crosses `revealThreshold`",
247
+ "name": "scratch-reveal"
248
+ }
249
+ ],
250
+ "attributes": [
251
+ {
252
+ "name": "reveal-threshold",
253
+ "type": {
254
+ "text": "number"
255
+ },
256
+ "default": "50",
257
+ "description": "Percentage (0–100) of the overlay that must be scratched before the `scratch-reveal` event fires.",
258
+ "fieldName": "revealThreshold"
259
+ }
260
+ ],
261
+ "superclass": {
262
+ "name": "UIBitElement",
263
+ "package": "@uibit/core"
264
+ },
265
+ "tagName": "uibit-scratch-reveal",
266
+ "customElement": true
267
+ }
268
+ ],
269
+ "exports": [
270
+ {
271
+ "kind": "js",
272
+ "name": "ScratchReveal",
273
+ "declaration": {
274
+ "name": "ScratchReveal",
275
+ "module": "src/scratch-reveal.ts"
276
+ }
277
+ },
278
+ {
279
+ "kind": "custom-element-definition",
280
+ "name": "uibit-scratch-reveal",
281
+ "declaration": {
282
+ "name": "ScratchReveal",
283
+ "module": "src/scratch-reveal.ts"
284
+ }
285
+ },
286
+ {
287
+ "kind": "js",
288
+ "name": "default",
289
+ "declaration": {
290
+ "name": "ScratchReveal",
291
+ "module": "src/scratch-reveal.ts"
292
+ }
293
+ }
294
+ ]
295
+ },
296
+ {
297
+ "kind": "javascript-module",
298
+ "path": "src/styles.ts",
299
+ "declarations": [
300
+ {
301
+ "kind": "variable",
302
+ "name": "styles",
303
+ "default": "css` :host { display: block; --uibit-scratch-reveal-width: 25rem; --uibit-scratch-reveal-height: 12.5rem; --uibit-scratch-reveal-overlay-color: #d1d5db; --uibit-scratch-reveal-cursor: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 32 32\"><circle cx=\"16\" cy=\"16\" r=\"13\" fill=\"%23111\" opacity=\"0.5\"/><circle cx=\"16\" cy=\"16\" r=\"12\" fill=\"none\" stroke=\"white\" stroke-width=\"2\"/><circle cx=\"16\" cy=\"16\" r=\"4\" fill=\"white\"/></svg>') 16 16, crosshair; --uibit-scratch-reveal-brush-size: 3rem; } .scratch-container { position: relative; width: var(--uibit-scratch-reveal-width); height: var(--uibit-scratch-reveal-height); overflow: hidden; border-radius: var(--uibit-scratch-reveal-border-radius, 0.5rem); background: var(--uibit-scratch-reveal-background, #f3f4f6); user-select: none; touch-action: none; } .content { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: var(--uibit-scratch-reveal-padding, 1rem); font-size: var(--uibit-scratch-reveal-font-size, var(--uibit-font-size-base, 1rem)); font-weight: var(--uibit-scratch-reveal-font-weight, var(--uibit-font-weight-semibold, 600)); color: var(--uibit-scratch-reveal-color, #111827); text-align: center; word-break: break-word; z-index: 1; } canvas { position: absolute; inset: 0; cursor: var(--uibit-scratch-reveal-cursor); z-index: 2; display: block; } .instructions { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: var(--uibit-scratch-reveal-instructions-color, rgba(0, 0, 0, 0.4)); font-size: var(--uibit-scratch-reveal-instructions-font-size, var(--uibit-font-size-sm, 0.875rem)); pointer-events: none; z-index: 3; } .instructions-text { display: block; margin-bottom: 0.5rem; } `"
304
+ }
305
+ ],
306
+ "exports": [
307
+ {
308
+ "kind": "js",
309
+ "name": "styles",
310
+ "declaration": {
311
+ "name": "styles",
312
+ "module": "src/styles.ts"
313
+ }
314
+ }
315
+ ]
316
+ },
317
+ {
318
+ "kind": "javascript-module",
319
+ "path": "src/types.ts",
320
+ "declarations": [],
321
+ "exports": []
322
+ }
323
+ ]
324
+ }
@@ -0,0 +1,28 @@
1
+ import { Component, ChangeDetectionStrategy, ElementRef, input, effect, output, numberAttribute } from '@angular/core';
2
+ import '@uibit/scratch-reveal';
3
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
4
+
5
+ @Component({
6
+ selector: 'uibit-scratch-reveal',
7
+ template: '<ng-content></ng-content>',
8
+ changeDetection: ChangeDetectionStrategy.OnPush,
9
+ standalone: true,
10
+ host: {
11
+ '(scratch-progress)': 'scratchProgress.emit($event)',
12
+ '(scratch-reveal)': 'scratchReveal.emit($event)'
13
+ }
14
+ })
15
+ export class NgxScratchReveal {
16
+ constructor(private el: ElementRef<HTMLElementClass>) {
17
+ effect(() => {
18
+ if (this.el.nativeElement) {
19
+ this.el.nativeElement.revealThreshold = this.revealThreshold();
20
+ }
21
+ });
22
+ }
23
+
24
+ readonly revealThreshold = input<number, any>(50, { transform: numberAttribute });
25
+
26
+ readonly scratchProgress = output<CustomEvent<{ percentage: number }>>();
27
+ readonly scratchReveal = output<CustomEvent<{ percentage: number }>>();
28
+ }
@@ -0,0 +1,10 @@
1
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
2
+ import '@uibit/scratch-reveal';
3
+
4
+ declare global {
5
+ namespace astroHTML.JSX {
6
+ interface IntrinsicElements {
7
+ 'uibit-scratch-reveal': Partial<HTMLElementClass> & astroHTML.JSX.HTMLAttributes;
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,7 @@
1
+ import { defineNuxtPlugin } from '#app';
2
+
3
+ export default defineNuxtPlugin(() => {
4
+ if (process.client) {
5
+ import('@uibit/scratch-reveal');
6
+ }
7
+ });
@@ -0,0 +1,13 @@
1
+ import type { JSX } from 'preact';
2
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
3
+ import '@uibit/scratch-reveal';
4
+
5
+ declare module 'preact' {
6
+ namespace JSX {
7
+ interface IntrinsicElements {
8
+ 'uibit-scratch-reveal': JSX.HTMLAttributes<HTMLElementClass> & {
9
+ revealThreshold?: number;
10
+ };
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import { component$, Slot } from '@builder.io/qwik';
2
+ import '@uibit/scratch-reveal';
3
+
4
+ export const ScratchReveal = component$<any>((props) => {
5
+ return (
6
+ <uibit-scratch-reveal {...props}>
7
+ <Slot />
8
+ </uibit-scratch-reveal>
9
+ );
10
+ });
@@ -0,0 +1,19 @@
1
+ import type { HTMLAttributes, ClassAttributes } from 'react';
2
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
3
+ import '@uibit/scratch-reveal';
4
+
5
+ declare global {
6
+ namespace React {
7
+ namespace JSX {
8
+ interface IntrinsicElements {
9
+ 'uibit-scratch-reveal': ClassAttributes<HTMLElementClass> & HTMLAttributes<HTMLElementClass> & {
10
+ children?: React.ReactNode;
11
+ class?: string;
12
+ revealThreshold?: number;
13
+ onScratchProgress?: (event: any) => void;
14
+ onScratchReveal?: (event: any) => void;
15
+ };
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ import type { JSX } from 'solid-js';
2
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
3
+ import '@uibit/scratch-reveal';
4
+
5
+ declare module 'solid-js' {
6
+ namespace JSX {
7
+ interface IntrinsicElements {
8
+ 'uibit-scratch-reveal': Partial<HTMLElementClass> & JSX.HTMLAttributes<HTMLElementClass> & {
9
+ revealThreshold?: number;
10
+ "on:scratch-progress"?: (event: CustomEvent) => void;
11
+ "on:scratch-reveal"?: (event: CustomEvent) => void;
12
+ };
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,12 @@
1
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
2
+ import '@uibit/scratch-reveal';
3
+
4
+ declare module '@stencil/core' {
5
+ export namespace JSX {
6
+ interface IntrinsicElements {
7
+ 'uibit-scratch-reveal': HTMLElementClass & {
8
+ revealThreshold?: number;
9
+ };
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import '@uibit/scratch-reveal';
3
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
4
+
5
+ let {
6
+ revealThreshold = undefined,
7
+ children
8
+ } = $props<{
9
+ children?: any;
10
+ revealThreshold?: number;
11
+
12
+ }>();
13
+
14
+ let elementRef: HTMLElementClass | null = $state(null);
15
+
16
+ $effect(() => {
17
+ if (elementRef && revealThreshold !== undefined) {
18
+ elementRef.revealThreshold = revealThreshold;
19
+ }
20
+ });
21
+
22
+ </script>
23
+
24
+ <uibit-scratch-reveal bind:this={elementRef} {...$$restProps}>
25
+
26
+ {#if children}
27
+ {@render children()}
28
+ {:else}
29
+ <slot />
30
+ {/if}
31
+ </uibit-scratch-reveal>
@@ -0,0 +1,27 @@
1
+ import { defineComponent, h } from 'vue';
2
+ import type { ScratchReveal as HTMLElementClass } from '@uibit/scratch-reveal';
3
+ import '@uibit/scratch-reveal';
4
+
5
+ export const ScratchReveal = defineComponent({
6
+ name: 'ScratchReveal',
7
+ props: {
8
+ revealThreshold: { type: [String, Number, Boolean, Array, Object] as any }
9
+ },
10
+ emits: ['scratch-progress', 'scratch-reveal'],
11
+ setup(props, { slots, emit }) {
12
+ return () => {
13
+ const eventListeners: Record<string, any> = {};
14
+ eventListeners['onScratch-progress'] = (event: Event) => {
15
+ emit('scratch-progress', event);
16
+ };
17
+ eventListeners['onScratch-reveal'] = (event: Event) => {
18
+ emit('scratch-reveal', event);
19
+ };
20
+
21
+ return h('uibit-scratch-reveal', {
22
+ ...props,
23
+ ...eventListeners
24
+ }, slots.default?.());
25
+ };
26
+ }
27
+ });
@@ -0,0 +1,3 @@
1
+ export { ScratchReveal } from './scratch-reveal';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { ScratchReveal } from './scratch-reveal';
2
+ export * from './types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,cAAc,SAAS,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { UIBitElement } from '@uibit/core';
2
+ /**
3
+ * Canvas-based scratch card that reveals slotted content as the user
4
+ * scratches over a configurable overlay layer.
5
+ *
6
+ * @fires {{ percentage: number }} scratch-progress - Fired as the user scratches; `detail.percentage` is 0–100
7
+ * @fires {{ percentage: number }} scratch-reveal - Fired once when the revealed area crosses `revealThreshold`
8
+ *
9
+ * @slot - The content revealed beneath the scratch overlay
10
+ *
11
+ * @cssprop [--uibit-scratch-reveal-width=25rem] - Width of the scratch card
12
+ * @cssprop [--uibit-scratch-reveal-height=12.5rem] - Height of the scratch card
13
+ * @cssprop [--uibit-scratch-reveal-border-radius=0.5rem] - Border radius of the card
14
+ * @cssprop [--uibit-scratch-reveal-background=#f3f4f6] - Background color of the revealed content area
15
+ * @cssprop [--uibit-scratch-reveal-padding=1rem] - Padding of the revealed content area
16
+ * @cssprop [--uibit-scratch-reveal-font-size=1rem] - Font size of the revealed content
17
+ * @cssprop [--uibit-scratch-reveal-font-weight=600] - Font weight of the revealed content
18
+ * @cssprop [--uibit-scratch-reveal-color=#111827] - Text color of the revealed content
19
+ * @cssprop [--uibit-scratch-reveal-overlay-color=#d1d5db] - Fill color of the scratchable overlay
20
+ * @cssprop [--uibit-scratch-reveal-instructions-color=rgba(0,0,0,0.4)] - Color of the scratch instruction hint
21
+ * @cssprop [--uibit-scratch-reveal-instructions-font-size=0.875rem] - Font size of the scratch instruction hint
22
+ */
23
+ export declare class ScratchReveal extends UIBitElement {
24
+ static styles: import("lit").CSSResult;
25
+ /** Percentage (0–100) of the overlay that must be scratched before the `scratch-reveal` event fires. */
26
+ revealThreshold: number;
27
+ private _scratchProgress;
28
+ get brushSize(): number;
29
+ private isRevealed;
30
+ private showInstructions;
31
+ private canvas?;
32
+ private ctx?;
33
+ private isDrawing;
34
+ private _rafId?;
35
+ connectedCallback(): void;
36
+ firstUpdated(): void;
37
+ private setupCanvas;
38
+ private drawOverlay;
39
+ private attachEventListeners;
40
+ private startScratching;
41
+ private stopScratching;
42
+ private scratch;
43
+ private calculateRevealPercentage;
44
+ disconnectedCallback(): void;
45
+ reset(): void;
46
+ render(): import("lit").TemplateResult<1>;
47
+ }
48
+ export default ScratchReveal;
49
+ //# sourceMappingURL=scratch-reveal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scratch-reveal.d.ts","sourceRoot":"","sources":["../src/scratch-reveal.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,YAAY,EAAE,MAAM,aAAa,CAAC;AAI/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBACa,aAAc,SAAQ,YAAY;IAC7C,MAAM,CAAC,MAAM,0BAAU;IAEvB,wGAAwG;IAC7C,eAAe,SAAM;IAEvE,OAAO,CAAC,gBAAgB,CAAK;IAEtC,IAAI,SAAS,IAAI,MAAM,CAStB;IAEQ,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAQ;IAEzC,OAAO,CAAC,MAAM,CAAC,CAAoB;IACnC,OAAO,CAAC,GAAG,CAAC,CAAkC;IAC9C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAC,CAAS;IAExB,iBAAiB,SAEhB;IAED,YAAY,SAEX;IAED,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,OAAO;IAuBf,OAAO,CAAC,yBAAyB;IA6BjC,oBAAoB,SAMnB;IAED,KAAK,SAQJ;IAED,MAAM,oCAgBL;CACF;eAEc,aAAa"}
@@ -0,0 +1,207 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html } from 'lit';
8
+ import { customElement, msg, UIBitElement } from '@uibit/core';
9
+ import { property, state } from 'lit/decorators.js';
10
+ import { styles } from './styles';
11
+ /**
12
+ * Canvas-based scratch card that reveals slotted content as the user
13
+ * scratches over a configurable overlay layer.
14
+ *
15
+ * @fires {{ percentage: number }} scratch-progress - Fired as the user scratches; `detail.percentage` is 0–100
16
+ * @fires {{ percentage: number }} scratch-reveal - Fired once when the revealed area crosses `revealThreshold`
17
+ *
18
+ * @slot - The content revealed beneath the scratch overlay
19
+ *
20
+ * @cssprop [--uibit-scratch-reveal-width=25rem] - Width of the scratch card
21
+ * @cssprop [--uibit-scratch-reveal-height=12.5rem] - Height of the scratch card
22
+ * @cssprop [--uibit-scratch-reveal-border-radius=0.5rem] - Border radius of the card
23
+ * @cssprop [--uibit-scratch-reveal-background=#f3f4f6] - Background color of the revealed content area
24
+ * @cssprop [--uibit-scratch-reveal-padding=1rem] - Padding of the revealed content area
25
+ * @cssprop [--uibit-scratch-reveal-font-size=1rem] - Font size of the revealed content
26
+ * @cssprop [--uibit-scratch-reveal-font-weight=600] - Font weight of the revealed content
27
+ * @cssprop [--uibit-scratch-reveal-color=#111827] - Text color of the revealed content
28
+ * @cssprop [--uibit-scratch-reveal-overlay-color=#d1d5db] - Fill color of the scratchable overlay
29
+ * @cssprop [--uibit-scratch-reveal-instructions-color=rgba(0,0,0,0.4)] - Color of the scratch instruction hint
30
+ * @cssprop [--uibit-scratch-reveal-instructions-font-size=0.875rem] - Font size of the scratch instruction hint
31
+ */
32
+ let ScratchReveal = class ScratchReveal extends UIBitElement {
33
+ constructor() {
34
+ super(...arguments);
35
+ /** Percentage (0–100) of the overlay that must be scratched before the `scratch-reveal` event fires. */
36
+ this.revealThreshold = 50;
37
+ this._scratchProgress = 0;
38
+ this.isRevealed = false;
39
+ this.showInstructions = true;
40
+ this.isDrawing = false;
41
+ }
42
+ static { this.styles = styles; }
43
+ get brushSize() {
44
+ if (typeof window === 'undefined')
45
+ return 80;
46
+ const val = getComputedStyle(this).getPropertyValue('--uibit-scratch-reveal-brush-size').trim();
47
+ if (!val)
48
+ return 80;
49
+ if (val.endsWith('rem')) {
50
+ return parseFloat(val) * parseFloat(getComputedStyle(document.documentElement).fontSize);
51
+ }
52
+ if (val.endsWith('px'))
53
+ return parseFloat(val);
54
+ return parseFloat(val) || 80;
55
+ }
56
+ connectedCallback() {
57
+ super.connectedCallback();
58
+ }
59
+ firstUpdated() {
60
+ this.setupCanvas();
61
+ }
62
+ setupCanvas() {
63
+ const container = this.shadowRoot?.querySelector('.scratch-container');
64
+ if (!container)
65
+ return;
66
+ this.canvas = this.shadowRoot?.querySelector('canvas');
67
+ if (!this.canvas)
68
+ return;
69
+ const rect = container.getBoundingClientRect();
70
+ this.canvas.width = rect.width * window.devicePixelRatio;
71
+ this.canvas.height = rect.height * window.devicePixelRatio;
72
+ this.ctx = this.canvas.getContext('2d', { willReadFrequently: true });
73
+ if (!this.ctx)
74
+ return;
75
+ this.ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
76
+ this.drawOverlay();
77
+ this.attachEventListeners();
78
+ }
79
+ drawOverlay() {
80
+ if (!this.ctx || !this.canvas)
81
+ return;
82
+ this.ctx.fillStyle = 'var(--uibit-scratch-reveal-overlay-color, #c0c0c0)';
83
+ this.ctx.fillRect(0, 0, this.canvas.width / window.devicePixelRatio, this.canvas.height / window.devicePixelRatio);
84
+ }
85
+ attachEventListeners() {
86
+ if (!this.canvas)
87
+ return;
88
+ this.listen(this.canvas, 'mousedown', (e) => this.startScratching(e));
89
+ this.listen(this.canvas, 'mousemove', (e) => this.scratch(e));
90
+ this.listen(this.canvas, 'mouseup', () => this.stopScratching());
91
+ this.listen(this.canvas, 'mouseleave', () => this.stopScratching());
92
+ this.listen(this.canvas, 'touchstart', (e) => {
93
+ this.isDrawing = true;
94
+ this.showInstructions = false;
95
+ const touch = e.touches[0];
96
+ if (touch)
97
+ this.scratch(touch);
98
+ }, { passive: true });
99
+ this.listen(this.canvas, 'touchmove', (e) => {
100
+ if (e.cancelable)
101
+ e.preventDefault();
102
+ const touch = e.touches[0];
103
+ if (touch)
104
+ this.scratch(touch);
105
+ }, { passive: false });
106
+ this.listen(this.canvas, 'touchend', () => this.stopScratching());
107
+ this.listen(this.canvas, 'touchcancel', () => this.stopScratching());
108
+ }
109
+ startScratching(e) {
110
+ this.isDrawing = true;
111
+ this.showInstructions = false;
112
+ this.scratch(e);
113
+ }
114
+ stopScratching() {
115
+ this.isDrawing = false;
116
+ }
117
+ scratch(e) {
118
+ if (!this.isDrawing || !this.ctx || !this.canvas)
119
+ return;
120
+ const rect = this.canvas.getBoundingClientRect();
121
+ const x = (e.clientX - rect.left) * window.devicePixelRatio;
122
+ const y = (e.clientY - rect.top) * window.devicePixelRatio;
123
+ const r = (this.brushSize * window.devicePixelRatio) / 2;
124
+ this.ctx.save();
125
+ this.ctx.globalCompositeOperation = 'destination-out';
126
+ this.ctx.beginPath();
127
+ this.ctx.arc(x, y, r, 0, Math.PI * 2);
128
+ this.ctx.fill();
129
+ this.ctx.restore();
130
+ if (!this._rafId) {
131
+ this._rafId = requestAnimationFrame(() => {
132
+ this._rafId = undefined;
133
+ this.calculateRevealPercentage();
134
+ });
135
+ }
136
+ }
137
+ calculateRevealPercentage() {
138
+ if (!this.ctx || !this.canvas)
139
+ return;
140
+ const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
141
+ const data = imageData.data;
142
+ let revealed = 0;
143
+ for (let i = 3; i < data.length; i += 4) {
144
+ if (data[i] === 0) {
145
+ revealed++;
146
+ }
147
+ }
148
+ const newPercentage = Math.round((revealed / (data.length / 4)) * 100);
149
+ this._scratchProgress = newPercentage;
150
+ this.dispatchCustomEvent('scratch-progress', { percentage: newPercentage });
151
+ if (newPercentage >= this.revealThreshold && !this.isRevealed) {
152
+ this.isRevealed = true;
153
+ this.dispatchCustomEvent('scratch-reveal', { percentage: newPercentage });
154
+ }
155
+ }
156
+ disconnectedCallback() {
157
+ super.disconnectedCallback();
158
+ if (this._rafId) {
159
+ cancelAnimationFrame(this._rafId);
160
+ this._rafId = undefined;
161
+ }
162
+ }
163
+ reset() {
164
+ this.isRevealed = false;
165
+ this.showInstructions = true;
166
+ this._scratchProgress = 0;
167
+ if (this.ctx && this.canvas) {
168
+ this.ctx.fillStyle = 'var(--uibit-scratch-reveal-overlay-color, #c0c0c0)';
169
+ this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
170
+ }
171
+ }
172
+ render() {
173
+ return html `
174
+ <div part="container" class="scratch-container" role="img" aria-label=${msg('Scratch-off panel to reveal content')} aria-valuenow=${this._scratchProgress}>
175
+ <div class="content" part="content">
176
+ <slot></slot>
177
+ </div>
178
+ <canvas part="canvas"></canvas>
179
+ ${this.showInstructions
180
+ ? html `
181
+ <div class="instructions" part="instructions">
182
+ <span class="instructions-text">${msg('Scratch to reveal')}</span>
183
+ </div>
184
+ `
185
+ : ''}
186
+ </div>
187
+ `;
188
+ }
189
+ };
190
+ __decorate([
191
+ property({ type: Number, attribute: 'reveal-threshold' })
192
+ ], ScratchReveal.prototype, "revealThreshold", void 0);
193
+ __decorate([
194
+ state()
195
+ ], ScratchReveal.prototype, "_scratchProgress", void 0);
196
+ __decorate([
197
+ state()
198
+ ], ScratchReveal.prototype, "isRevealed", void 0);
199
+ __decorate([
200
+ state()
201
+ ], ScratchReveal.prototype, "showInstructions", void 0);
202
+ ScratchReveal = __decorate([
203
+ customElement('uibit-scratch-reveal')
204
+ ], ScratchReveal);
205
+ export { ScratchReveal };
206
+ export default ScratchReveal;
207
+ //# sourceMappingURL=scratch-reveal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scratch-reveal.js","sourceRoot":"","sources":["../src/scratch-reveal.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;GAoBG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,YAAY;IAAxC;;QAGL,wGAAwG;QAC7C,oBAAe,GAAG,EAAE,CAAC;QAE/D,qBAAgB,GAAG,CAAC,CAAC;QAarB,eAAU,GAAG,KAAK,CAAC;QACnB,qBAAgB,GAAG,IAAI,CAAC;QAIjC,cAAS,GAAG,KAAK,CAAC;IAgK5B,CAAC;aAvLQ,WAAM,GAAG,MAAM,AAAT,CAAU;IAOvB,IAAI,SAAS;QACX,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,mCAAmC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChG,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC3F,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/C,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAUD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAC;IAC5B,CAAC;IAED,YAAY;QACV,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEO,WAAW;QACjB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,oBAAoB,CAAgB,CAAC;QACtF,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAsB,CAAC;QAC5E,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,MAAM,IAAI,GAAG,SAAS,CAAC,qBAAqB,EAAE,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAE3D,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAEjE,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAC9B,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEtC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,oDAAoD,CAAC;QAC1E,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACrH,CAAC;IAEO,oBAAoB;QAC1B,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAe,CAAC,CAAC,CAAC;QACpF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAe,CAAC,CAAC,CAAC;QAC5E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QAEpE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;YAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;YAC9B,MAAM,KAAK,GAAI,CAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,KAAK;gBAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE;YAC1C,IAAK,CAAgB,CAAC,UAAU;gBAAG,CAAgB,CAAC,cAAc,EAAE,CAAC;YACrE,MAAM,KAAK,GAAI,CAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,KAAK;gBAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAEvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;IACvE,CAAC;IAEO,eAAe,CAAC,CAAa;QACnC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAEO,OAAO,CAAC,CAAqB;QACnC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAC5D,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAC3D,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAEzD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAChB,IAAI,CAAC,GAAG,CAAC,wBAAwB,GAAG,iBAAiB,CAAC;QACtD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAChB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAEnB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,GAAG,EAAE;gBACvC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;gBACxB,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,yBAAyB;QAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CACrC,CAAC,EACD,CAAC,EACD,IAAI,CAAC,MAAM,CAAC,KAAK,EACjB,IAAI,CAAC,MAAM,CAAC,MAAM,CACnB,CAAC;QACF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;QAE5B,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClB,QAAQ,EAAE,CAAC;YACb,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QACvE,IAAI,CAAC,gBAAgB,GAAG,aAAa,CAAC;QAEtC,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;QAE5E,IAAI,aAAa,IAAI,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YAC9D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,oBAAoB;QAClB,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,oDAAoD,CAAC;YAC1E,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;8EAC+D,GAAG,CAAC,qCAAqC,CAAC,kBAAkB,IAAI,CAAC,gBAAgB;;;;;UAKrJ,IAAI,CAAC,gBAAgB;YACvB,CAAC,CAAC,IAAI,CAAA;;kDAEoC,GAAG,CAAC,mBAAmB,CAAC;;aAE7D;YACL,CAAC,CAAC,EAAE;;KAEP,CAAC;IACJ,CAAC;CACF,CAAA;AApL4D;IAA1D,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;sDAAsB;AAE/D;IAAhB,KAAK,EAAE;uDAA8B;AAarB;IAAhB,KAAK,EAAE;iDAA4B;AACnB;IAAhB,KAAK,EAAE;uDAAiC;AApB9B,aAAa;IADzB,aAAa,CAAC,sBAAsB,CAAC;GACzB,aAAa,CAwLzB;;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const styles: import("lit").CSSResult;
2
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,yBA4DlB,CAAC"}
package/dist/styles.js ADDED
@@ -0,0 +1,63 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ --uibit-scratch-reveal-width: 25rem;
6
+ --uibit-scratch-reveal-height: 12.5rem;
7
+ --uibit-scratch-reveal-overlay-color: #d1d5db;
8
+ --uibit-scratch-reveal-cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><circle cx="16" cy="16" r="13" fill="%23111" opacity="0.5"/><circle cx="16" cy="16" r="12" fill="none" stroke="white" stroke-width="2"/><circle cx="16" cy="16" r="4" fill="white"/></svg>') 16 16, crosshair;
9
+ --uibit-scratch-reveal-brush-size: 3rem;
10
+ }
11
+
12
+ .scratch-container {
13
+ position: relative;
14
+ width: var(--uibit-scratch-reveal-width);
15
+ height: var(--uibit-scratch-reveal-height);
16
+ overflow: hidden;
17
+ border-radius: var(--uibit-scratch-reveal-border-radius, 0.5rem);
18
+ background: var(--uibit-scratch-reveal-background, #f3f4f6);
19
+ user-select: none;
20
+ touch-action: none;
21
+ }
22
+
23
+ .content {
24
+ position: absolute;
25
+ inset: 0;
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ padding: var(--uibit-scratch-reveal-padding, 1rem);
30
+ font-size: var(--uibit-scratch-reveal-font-size, var(--uibit-font-size-base, 1rem));
31
+ font-weight: var(--uibit-scratch-reveal-font-weight, var(--uibit-font-weight-semibold, 600));
32
+ color: var(--uibit-scratch-reveal-color, #111827);
33
+ text-align: center;
34
+ word-break: break-word;
35
+ z-index: 1;
36
+ }
37
+
38
+ canvas {
39
+ position: absolute;
40
+ inset: 0;
41
+ cursor: var(--uibit-scratch-reveal-cursor);
42
+ z-index: 2;
43
+ display: block;
44
+ }
45
+
46
+ .instructions {
47
+ position: absolute;
48
+ top: 50%;
49
+ left: 50%;
50
+ transform: translate(-50%, -50%);
51
+ text-align: center;
52
+ color: var(--uibit-scratch-reveal-instructions-color, rgba(0, 0, 0, 0.4));
53
+ font-size: var(--uibit-scratch-reveal-instructions-font-size, var(--uibit-font-size-sm, 0.875rem));
54
+ pointer-events: none;
55
+ z-index: 3;
56
+ }
57
+
58
+ .instructions-text {
59
+ display: block;
60
+ margin-bottom: 0.5rem;
61
+ }
62
+ `;
63
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DxB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type ScratchReveal from './scratch-reveal';
2
+ export interface ScratchRevealDetail {
3
+ revealPercentage: number;
4
+ }
5
+ export interface ScratchProgressDetail {
6
+ revealPercentage: number;
7
+ }
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'uibit-scratch-reveal': ScratchReveal;
11
+ }
12
+ }
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,OAAO,CAAC,MAAM,CAAC;IACf,UAAU,qBAAqB;QAC3B,sBAAsB,EAAE,aAAa,CAAC;KACzC;CACA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@uibit/scratch-reveal",
3
+ "version": "0.1.0",
4
+ "description": "A gamified, accessible scratch-off panel component that reveals hidden content. Users can scratch off the overlay canvas layer by dragging or touching.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./scratch-reveal.css": "./dist/scratch-reveal.css",
14
+ "./custom-elements.json": "./custom-elements.json",
15
+ "./react": "./dist/frameworks/react/index.d.ts",
16
+ "./vue": "./dist/frameworks/vue/index.ts",
17
+ "./svelte": "./dist/frameworks/svelte/index.svelte",
18
+ "./angular": "./dist/frameworks/angular/index.ts",
19
+ "./solid": "./dist/frameworks/solid/index.d.ts",
20
+ "./astro": "./dist/frameworks/astro/index.astro",
21
+ "./qwik": "./dist/frameworks/qwik/index.tsx",
22
+ "./nuxt": "./dist/frameworks/nuxt/index.ts",
23
+ "./preact": "./dist/frameworks/preact/index.d.ts",
24
+ "./stencil": "./dist/frameworks/stencil/index.d.ts"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "package.json",
29
+ "README.md",
30
+ "LICENSE",
31
+ "custom-elements.json"
32
+ ],
33
+ "keywords": [
34
+ "scratch-reveal",
35
+ "web-component",
36
+ "lit",
37
+ "gamified",
38
+ "interactive",
39
+ "promo",
40
+ "accessible",
41
+ "a11y"
42
+ ],
43
+ "author": "Jonathan Rawlings",
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/Rawlings/uibit",
48
+ "directory": "packages/components/scratch-reveal"
49
+ },
50
+ "dependencies": {
51
+ "@uibit/core": "0.1.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.19.43",
55
+ "lit": "^3.3.3",
56
+ "typescript": "7.0.2",
57
+ "@uibit/codegen": "0.1.0"
58
+ },
59
+ "peerDependencies": {
60
+ "lit": "^3.0.0",
61
+ "react": ">=18",
62
+ "vue": ">=3",
63
+ "svelte": ">=4 || ^5",
64
+ "@angular/core": ">=14"
65
+ },
66
+ "customElements": "custom-elements.json",
67
+ "peerDependenciesMeta": {
68
+ "react": {
69
+ "optional": true
70
+ },
71
+ "vue": {
72
+ "optional": true
73
+ },
74
+ "svelte": {
75
+ "optional": true
76
+ },
77
+ "@angular/core": {
78
+ "optional": true
79
+ }
80
+ },
81
+ "uibit": {
82
+ "id": "scratch-reveal",
83
+ "title": "Scratch Reveal",
84
+ "category": "Media",
85
+ "tagName": "uibit-scratch-reveal"
86
+ },
87
+ "scripts": {
88
+ "build": "cem analyze --globs 'src/**/*.ts' --litelement && uibit-codegen --package . && tsc",
89
+ "dev": "concurrently \"cem analyze --globs 'src/**/*.ts' --litelement --watch\" \"tsc --watch\"",
90
+ "analyze": "cem analyze --globs 'src/**/*.ts' --litelement",
91
+ "typecheck": "tsc --noEmit"
92
+ }
93
+ }