@sealpixel/ui 1.0.0-rc.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.
Files changed (196) hide show
  1. package/LICENSE.md +59 -0
  2. package/README.md +10 -0
  3. package/dist/components/lumbra-button.d.ts +28 -0
  4. package/dist/components/lumbra-button.d.ts.map +1 -0
  5. package/dist/components/lumbra-button.js +87 -0
  6. package/dist/components/lumbra-button.js.map +1 -0
  7. package/dist/components/lumbra-editor.d.ts +226 -0
  8. package/dist/components/lumbra-editor.d.ts.map +1 -0
  9. package/dist/components/lumbra-editor.js +873 -0
  10. package/dist/components/lumbra-editor.js.map +1 -0
  11. package/dist/components/lumbra-nav.d.ts +48 -0
  12. package/dist/components/lumbra-nav.d.ts.map +1 -0
  13. package/dist/components/lumbra-nav.js +159 -0
  14. package/dist/components/lumbra-nav.js.map +1 -0
  15. package/dist/components/lumbra-slider.d.ts +48 -0
  16. package/dist/components/lumbra-slider.d.ts.map +1 -0
  17. package/dist/components/lumbra-slider.js +168 -0
  18. package/dist/components/lumbra-slider.js.map +1 -0
  19. package/dist/components/lumbra-stage.d.ts +92 -0
  20. package/dist/components/lumbra-stage.d.ts.map +1 -0
  21. package/dist/components/lumbra-stage.js +344 -0
  22. package/dist/components/lumbra-stage.js.map +1 -0
  23. package/dist/components/lumbra-toolbar.d.ts +30 -0
  24. package/dist/components/lumbra-toolbar.d.ts.map +1 -0
  25. package/dist/components/lumbra-toolbar.js +127 -0
  26. package/dist/components/lumbra-toolbar.js.map +1 -0
  27. package/dist/components/pincel-button.d.ts +28 -0
  28. package/dist/components/pincel-button.d.ts.map +1 -0
  29. package/dist/components/pincel-button.js +87 -0
  30. package/dist/components/pincel-button.js.map +1 -0
  31. package/dist/components/pincel-editor.d.ts +195 -0
  32. package/dist/components/pincel-editor.d.ts.map +1 -0
  33. package/dist/components/pincel-editor.js +794 -0
  34. package/dist/components/pincel-editor.js.map +1 -0
  35. package/dist/components/pincel-nav.d.ts +33 -0
  36. package/dist/components/pincel-nav.d.ts.map +1 -0
  37. package/dist/components/pincel-nav.js +147 -0
  38. package/dist/components/pincel-nav.js.map +1 -0
  39. package/dist/components/pincel-slider.d.ts +48 -0
  40. package/dist/components/pincel-slider.d.ts.map +1 -0
  41. package/dist/components/pincel-slider.js +168 -0
  42. package/dist/components/pincel-slider.js.map +1 -0
  43. package/dist/components/pincel-stage.d.ts +66 -0
  44. package/dist/components/pincel-stage.d.ts.map +1 -0
  45. package/dist/components/pincel-stage.js +233 -0
  46. package/dist/components/pincel-stage.js.map +1 -0
  47. package/dist/components/pincel-toolbar.d.ts +30 -0
  48. package/dist/components/pincel-toolbar.d.ts.map +1 -0
  49. package/dist/components/pincel-toolbar.js +127 -0
  50. package/dist/components/pincel-toolbar.js.map +1 -0
  51. package/dist/components/sealpixel-button.d.ts +28 -0
  52. package/dist/components/sealpixel-button.d.ts.map +1 -0
  53. package/dist/components/sealpixel-button.js +117 -0
  54. package/dist/components/sealpixel-button.js.map +1 -0
  55. package/dist/components/sealpixel-editor.d.ts +226 -0
  56. package/dist/components/sealpixel-editor.d.ts.map +1 -0
  57. package/dist/components/sealpixel-editor.js +1245 -0
  58. package/dist/components/sealpixel-editor.js.map +1 -0
  59. package/dist/components/sealpixel-nav.d.ts +48 -0
  60. package/dist/components/sealpixel-nav.d.ts.map +1 -0
  61. package/dist/components/sealpixel-nav.js +159 -0
  62. package/dist/components/sealpixel-nav.js.map +1 -0
  63. package/dist/components/sealpixel-slider.d.ts +75 -0
  64. package/dist/components/sealpixel-slider.d.ts.map +1 -0
  65. package/dist/components/sealpixel-slider.js +269 -0
  66. package/dist/components/sealpixel-slider.js.map +1 -0
  67. package/dist/components/sealpixel-stage.d.ts +118 -0
  68. package/dist/components/sealpixel-stage.d.ts.map +1 -0
  69. package/dist/components/sealpixel-stage.js +409 -0
  70. package/dist/components/sealpixel-stage.js.map +1 -0
  71. package/dist/components/sealpixel-stepper.d.ts +69 -0
  72. package/dist/components/sealpixel-stepper.d.ts.map +1 -0
  73. package/dist/components/sealpixel-stepper.js +248 -0
  74. package/dist/components/sealpixel-stepper.js.map +1 -0
  75. package/dist/components/sealpixel-toolbar.d.ts +30 -0
  76. package/dist/components/sealpixel-toolbar.d.ts.map +1 -0
  77. package/dist/components/sealpixel-toolbar.js +149 -0
  78. package/dist/components/sealpixel-toolbar.js.map +1 -0
  79. package/dist/controllers/gesture-controller.d.ts +65 -0
  80. package/dist/controllers/gesture-controller.d.ts.map +1 -0
  81. package/dist/controllers/gesture-controller.js +125 -0
  82. package/dist/controllers/gesture-controller.js.map +1 -0
  83. package/dist/controllers/session-controller.d.ts +15 -0
  84. package/dist/controllers/session-controller.d.ts.map +1 -0
  85. package/dist/controllers/session-controller.js +37 -0
  86. package/dist/controllers/session-controller.js.map +1 -0
  87. package/dist/define.d.ts +21 -0
  88. package/dist/define.d.ts.map +1 -0
  89. package/dist/define.js +27 -0
  90. package/dist/define.js.map +1 -0
  91. package/dist/i18n.d.ts +11 -0
  92. package/dist/i18n.d.ts.map +1 -0
  93. package/dist/i18n.js +27 -0
  94. package/dist/i18n.js.map +1 -0
  95. package/dist/icons.d.ts +32 -0
  96. package/dist/icons.d.ts.map +1 -0
  97. package/dist/icons.js +45 -0
  98. package/dist/icons.js.map +1 -0
  99. package/dist/index.d.ts +18 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +17 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/locales/de.d.ts +3 -0
  104. package/dist/locales/de.d.ts.map +1 -0
  105. package/dist/locales/de.js +132 -0
  106. package/dist/locales/de.js.map +1 -0
  107. package/dist/locales/en.d.ts +3 -0
  108. package/dist/locales/en.d.ts.map +1 -0
  109. package/dist/locales/en.js +132 -0
  110. package/dist/locales/en.js.map +1 -0
  111. package/dist/locales/es.d.ts +3 -0
  112. package/dist/locales/es.d.ts.map +1 -0
  113. package/dist/locales/es.js +132 -0
  114. package/dist/locales/es.js.map +1 -0
  115. package/dist/locales/fr.d.ts +3 -0
  116. package/dist/locales/fr.d.ts.map +1 -0
  117. package/dist/locales/fr.js +132 -0
  118. package/dist/locales/fr.js.map +1 -0
  119. package/dist/locales/index.d.ts +6 -0
  120. package/dist/locales/index.d.ts.map +1 -0
  121. package/dist/locales/index.js +13 -0
  122. package/dist/locales/index.js.map +1 -0
  123. package/dist/locales/ja.d.ts +3 -0
  124. package/dist/locales/ja.d.ts.map +1 -0
  125. package/dist/locales/ja.js +132 -0
  126. package/dist/locales/ja.js.map +1 -0
  127. package/dist/locales/pt.d.ts +3 -0
  128. package/dist/locales/pt.d.ts.map +1 -0
  129. package/dist/locales/pt.js +132 -0
  130. package/dist/locales/pt.js.map +1 -0
  131. package/dist/theme.d.ts +19 -0
  132. package/dist/theme.d.ts.map +1 -0
  133. package/dist/theme.js +150 -0
  134. package/dist/theme.js.map +1 -0
  135. package/dist/tool.d.ts +70 -0
  136. package/dist/tool.d.ts.map +1 -0
  137. package/dist/tool.js +2 -0
  138. package/dist/tool.js.map +1 -0
  139. package/dist/tools/annotate.d.ts +3 -0
  140. package/dist/tools/annotate.d.ts.map +1 -0
  141. package/dist/tools/annotate.js +436 -0
  142. package/dist/tools/annotate.js.map +1 -0
  143. package/dist/tools/crop-mask.d.ts +29 -0
  144. package/dist/tools/crop-mask.d.ts.map +1 -0
  145. package/dist/tools/crop-mask.js +75 -0
  146. package/dist/tools/crop-mask.js.map +1 -0
  147. package/dist/tools/crop.d.ts +11 -0
  148. package/dist/tools/crop.d.ts.map +1 -0
  149. package/dist/tools/crop.js +361 -0
  150. package/dist/tools/crop.js.map +1 -0
  151. package/dist/tools/delete-handle.d.ts +18 -0
  152. package/dist/tools/delete-handle.d.ts.map +1 -0
  153. package/dist/tools/delete-handle.js +61 -0
  154. package/dist/tools/delete-handle.js.map +1 -0
  155. package/dist/tools/filter.d.ts +3 -0
  156. package/dist/tools/filter.d.ts.map +1 -0
  157. package/dist/tools/filter.js +174 -0
  158. package/dist/tools/filter.js.map +1 -0
  159. package/dist/tools/finetune.d.ts +11 -0
  160. package/dist/tools/finetune.d.ts.map +1 -0
  161. package/dist/tools/finetune.js +98 -0
  162. package/dist/tools/finetune.js.map +1 -0
  163. package/dist/tools/frame.d.ts +3 -0
  164. package/dist/tools/frame.d.ts.map +1 -0
  165. package/dist/tools/frame.js +57 -0
  166. package/dist/tools/frame.js.map +1 -0
  167. package/dist/tools/index.d.ts +14 -0
  168. package/dist/tools/index.d.ts.map +1 -0
  169. package/dist/tools/index.js +41 -0
  170. package/dist/tools/index.js.map +1 -0
  171. package/dist/tools/redact.d.ts +3 -0
  172. package/dist/tools/redact.d.ts.map +1 -0
  173. package/dist/tools/redact.js +252 -0
  174. package/dist/tools/redact.js.map +1 -0
  175. package/dist/tools/resize.d.ts +3 -0
  176. package/dist/tools/resize.d.ts.map +1 -0
  177. package/dist/tools/resize.js +91 -0
  178. package/dist/tools/resize.js.map +1 -0
  179. package/dist/tools/sticker.d.ts +8 -0
  180. package/dist/tools/sticker.d.ts.map +1 -0
  181. package/dist/tools/sticker.js +156 -0
  182. package/dist/tools/sticker.js.map +1 -0
  183. package/dist/tools/watermark.d.ts +3 -0
  184. package/dist/tools/watermark.d.ts.map +1 -0
  185. package/dist/tools/watermark.js +102 -0
  186. package/dist/tools/watermark.js.map +1 -0
  187. package/dist/view-mapping.d.ts +23 -0
  188. package/dist/view-mapping.d.ts.map +1 -0
  189. package/dist/view-mapping.js +72 -0
  190. package/dist/view-mapping.js.map +1 -0
  191. package/package.json +55 -0
  192. package/themes/default.css +23 -0
  193. package/themes/high-contrast.css +30 -0
  194. package/themes/minimal.css +32 -0
  195. package/themes/nocturne.css +21 -0
  196. package/themes/studio.css +23 -0
@@ -0,0 +1,233 @@
1
+ import { css, html, LitElement, svg } from 'lit';
2
+ import { GestureController } from '../controllers/gesture-controller.js';
3
+ import { base } from '../theme.js';
4
+ /**
5
+ * Shows the preview on a canvas, fitted and zoomable, with an SVG overlay in
6
+ * image pixel coordinates for tool gizmos. Tier-A hints (CSS filter and
7
+ * transform) are applied to the canvas until the next preview arrives.
8
+ */
9
+ export class PincelStage extends LitElement {
10
+ static { this.styles = [
11
+ base,
12
+ css `
13
+ :host {
14
+ display: block;
15
+ position: relative;
16
+ overflow: hidden;
17
+ background-color: var(--pincel-color-bg);
18
+ background-image:
19
+ linear-gradient(45deg, var(--pincel-stage-checker-a) 25%, transparent 25%),
20
+ linear-gradient(-45deg, var(--pincel-stage-checker-a) 25%, transparent 25%),
21
+ linear-gradient(45deg, transparent 75%, var(--pincel-stage-checker-a) 75%),
22
+ linear-gradient(-45deg, transparent 75%, var(--pincel-stage-checker-a) 75%);
23
+ background-size: 16px 16px;
24
+ background-position: 0 0, 0 8px, 8px -8px, -8px 0;
25
+ touch-action: none;
26
+ user-select: none;
27
+ }
28
+ .viewport {
29
+ position: absolute;
30
+ inset: 0;
31
+ }
32
+ .content {
33
+ position: absolute;
34
+ left: 0;
35
+ top: 0;
36
+ transform-origin: 0 0;
37
+ will-change: transform;
38
+ }
39
+ canvas {
40
+ display: block;
41
+ image-rendering: auto;
42
+ transform-origin: 50% 50%;
43
+ box-shadow: var(--pincel-shadow, none);
44
+ }
45
+ svg.overlay {
46
+ position: absolute;
47
+ left: 0;
48
+ top: 0;
49
+ overflow: visible;
50
+ pointer-events: none;
51
+ }
52
+ svg.overlay [data-interactive] {
53
+ pointer-events: all;
54
+ }
55
+ .status {
56
+ position: absolute;
57
+ right: var(--pincel-space);
58
+ bottom: var(--pincel-space);
59
+ padding: 3px 9px;
60
+ border-radius: 999px;
61
+ background: color-mix(in srgb, var(--pincel-color-surface) 85%, transparent);
62
+ color: var(--pincel-color-fg-muted);
63
+ font-size: 12px;
64
+ font-variant-numeric: tabular-nums;
65
+ pointer-events: none;
66
+ backdrop-filter: blur(6px);
67
+ }
68
+ .pending {
69
+ position: absolute;
70
+ left: var(--pincel-space);
71
+ top: var(--pincel-space);
72
+ width: 8px;
73
+ height: 8px;
74
+ border-radius: 50%;
75
+ background: var(--pincel-color-accent);
76
+ opacity: 0.8;
77
+ }
78
+ `,
79
+ ]; }
80
+ static { this.properties = {
81
+ preview: { attribute: false },
82
+ pending: { type: Boolean },
83
+ overlay: { attribute: false },
84
+ hintFilter: { attribute: false },
85
+ hintTransform: { attribute: false },
86
+ zoom: { type: Number },
87
+ panEnabled: { type: Boolean },
88
+ }; }
89
+ constructor() {
90
+ super();
91
+ this.canvas = null;
92
+ this.drawnVersion = -1;
93
+ this.pan = { x: 0, y: 0 };
94
+ this.fitted = false;
95
+ this.resizeObserver = null;
96
+ this.gestures = new GestureController(this, {
97
+ drag: (e) => {
98
+ if (!this.panEnabled)
99
+ return;
100
+ this.pan = { x: this.pan.x + e.dx, y: this.pan.y + e.dy };
101
+ this.requestUpdate();
102
+ },
103
+ pinch: (e) => this.zoomAround(e.scale, e.cx, e.cy, e.dx, e.dy),
104
+ wheelZoom: (e) => this.zoomAround(e.factor, e.cx, e.cy, 0, 0),
105
+ wheelPan: (e) => {
106
+ this.pan = { x: this.pan.x + e.dx, y: this.pan.y + e.dy };
107
+ this.requestUpdate();
108
+ },
109
+ });
110
+ this.preview = null;
111
+ this.pending = false;
112
+ this.overlay = null;
113
+ this.hintFilter = '';
114
+ this.hintTransform = '';
115
+ this.zoom = 1;
116
+ this.panEnabled = true;
117
+ }
118
+ get geometry() {
119
+ return this.preview?.geometry ?? null;
120
+ }
121
+ get imageWidth() {
122
+ return this.preview?.image.width ?? 0;
123
+ }
124
+ get imageHeight() {
125
+ return this.preview?.image.height ?? 0;
126
+ }
127
+ /** Converts a client point into preview image pixels. */
128
+ toImage(clientX, clientY) {
129
+ const r = this.getBoundingClientRect();
130
+ return {
131
+ x: (clientX - r.left - this.pan.x) / this.zoom,
132
+ y: (clientY - r.top - this.pan.y) / this.zoom,
133
+ };
134
+ }
135
+ fit() {
136
+ const w = this.imageWidth;
137
+ const h = this.imageHeight;
138
+ if (!w || !h)
139
+ return;
140
+ const r = this.getBoundingClientRect();
141
+ const margin = 24;
142
+ const zoom = Math.min((r.width - margin) / w, (r.height - margin) / h, 4);
143
+ this.zoom = Math.max(zoom, 0.01);
144
+ this.pan = { x: (r.width - w * this.zoom) / 2, y: (r.height - h * this.zoom) / 2 };
145
+ this.fitted = true;
146
+ this.requestUpdate();
147
+ this.viewChanged();
148
+ }
149
+ /** Zoom or pan changed: overlays scale their gizmos by zoom and must re-render. */
150
+ viewChanged() {
151
+ this.dispatchEvent(new CustomEvent('stage-view', { detail: { zoom: this.zoom, pan: this.pan } }));
152
+ }
153
+ connectedCallback() {
154
+ super.connectedCallback();
155
+ this.resizeObserver = new ResizeObserver(() => {
156
+ if (this.fitted)
157
+ this.fit();
158
+ });
159
+ this.resizeObserver.observe(this);
160
+ }
161
+ disconnectedCallback() {
162
+ super.disconnectedCallback();
163
+ this.resizeObserver?.disconnect();
164
+ }
165
+ firstUpdated() {
166
+ this.canvas = this.renderRoot.querySelector('canvas');
167
+ this.gestures.attach(this.renderRoot.querySelector('.viewport'));
168
+ }
169
+ updated(changed) {
170
+ if (changed.has('preview'))
171
+ this.draw();
172
+ }
173
+ draw() {
174
+ const canvas = this.canvas;
175
+ const preview = this.preview;
176
+ if (!canvas || !preview)
177
+ return;
178
+ const { image } = preview;
179
+ const sizeChanged = canvas.width !== image.width || canvas.height !== image.height;
180
+ if (sizeChanged) {
181
+ canvas.width = image.width;
182
+ canvas.height = image.height;
183
+ }
184
+ if (preview.version !== this.drawnVersion || sizeChanged) {
185
+ const ctx = canvas.getContext('2d');
186
+ if (ctx) {
187
+ const data = new Uint8ClampedArray(image.data.byteLength);
188
+ data.set(image.data);
189
+ ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
190
+ }
191
+ this.drawnVersion = preview.version;
192
+ // A real preview landed: drop tier-A hints.
193
+ this.hintFilter = '';
194
+ this.hintTransform = '';
195
+ }
196
+ if (!this.fitted || sizeChanged)
197
+ this.fit();
198
+ }
199
+ zoomAround(factor, cx, cy, dx, dy) {
200
+ const next = Math.min(16, Math.max(0.05, this.zoom * factor));
201
+ const k = next / this.zoom;
202
+ this.pan = { x: cx - (cx - this.pan.x) * k + dx, y: cy - (cy - this.pan.y) * k + dy };
203
+ this.zoom = next;
204
+ this.fitted = false;
205
+ this.requestUpdate();
206
+ this.viewChanged();
207
+ }
208
+ render() {
209
+ const w = this.imageWidth;
210
+ const h = this.imageHeight;
211
+ const transform = `translate(${this.pan.x}px, ${this.pan.y}px) scale(${this.zoom})`;
212
+ return html `
213
+ <div class="viewport" part="viewport">
214
+ <div class="content" style="transform:${transform}">
215
+ <canvas
216
+ part="canvas"
217
+ width=${w}
218
+ height=${h}
219
+ style="filter:${this.hintFilter || 'none'};transform:${this.hintTransform || 'none'}"
220
+ role="img"
221
+ aria-label="preview"
222
+ ></canvas>
223
+ ${this.overlay
224
+ ? svg `<svg class="overlay" part="overlay" width=${w} height=${h} viewBox="0 0 ${w} ${h}">${this.overlay}</svg>`
225
+ : null}
226
+ </div>
227
+ </div>
228
+ ${this.pending ? html `<div class="pending" aria-hidden="true"></div>` : null}
229
+ <div class="status" part="status" aria-hidden="true">${Math.round(this.zoom * 100)}%</div>
230
+ `;
231
+ }
232
+ }
233
+ //# sourceMappingURL=pincel-stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pincel-stage.js","sourceRoot":"","sources":["../../src/components/pincel-stage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { LitElement } from 'lit';
2
+ import type { UiTool } from '../tool.js';
3
+ /** Tool switcher with roving tabindex. Horizontal on narrow layouts, vertical on wide. */
4
+ export declare class PincelToolbar extends LitElement {
5
+ static styles: import("lit").CSSResult[];
6
+ static properties: {
7
+ tools: {
8
+ attribute: boolean;
9
+ };
10
+ active: {
11
+ type: StringConstructor;
12
+ };
13
+ orientation: {
14
+ type: StringConstructor;
15
+ reflect: boolean;
16
+ };
17
+ t: {
18
+ attribute: boolean;
19
+ };
20
+ };
21
+ tools: UiTool[];
22
+ active: string | null;
23
+ orientation: 'horizontal' | 'vertical';
24
+ t: (key: string) => string;
25
+ constructor();
26
+ render(): import("lit").TemplateResult<1>;
27
+ private select;
28
+ private onKeydown;
29
+ }
30
+ //# sourceMappingURL=pincel-toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pincel-toolbar.d.ts","sourceRoot":"","sources":["../../src/components/pincel-toolbar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AAE5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,0FAA0F;AAC1F,qBAAa,aAAc,SAAQ,UAAU;IAC3C,OAAgB,MAAM,4BA4EpB;IAEF,OAAgB,UAAU;;;;;;;;;;;;;;MAKxB;IAEM,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,YAAY,GAAG,UAAU,CAAC;IACvC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;;IAU1B,MAAM;IAkBf,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,SAAS,CAiBf;CACH"}
@@ -0,0 +1,127 @@
1
+ import { css, html, LitElement } from 'lit';
2
+ import { base } from '../theme.js';
3
+ /** Tool switcher with roving tabindex. Horizontal on narrow layouts, vertical on wide. */
4
+ export class PincelToolbar extends LitElement {
5
+ static { this.styles = [
6
+ base,
7
+ css `
8
+ :host {
9
+ display: flex;
10
+ padding: 4px;
11
+ background: var(--pincel-color-surface);
12
+ border-top: 1px solid var(--pincel-color-border);
13
+ overflow: auto;
14
+ scrollbar-width: thin;
15
+ }
16
+ .tools {
17
+ display: flex;
18
+ gap: 4px;
19
+ /* Centres when it fits, scrolls from the first button when it does not. */
20
+ margin: auto;
21
+ }
22
+ :host([orientation='vertical']) {
23
+ border-top: none;
24
+ border-right: 1px solid var(--pincel-color-border);
25
+ }
26
+ :host([orientation='vertical']) .tools {
27
+ flex-direction: column;
28
+ margin: 0;
29
+ }
30
+ button {
31
+ min-width: var(--pincel-touch-target);
32
+ min-height: calc(var(--pincel-touch-target) + 10px);
33
+ border: 1px solid transparent;
34
+ border-radius: var(--pincel-radius);
35
+ background: transparent;
36
+ color: var(--pincel-color-fg-muted);
37
+ font: inherit;
38
+ font-size: 11px;
39
+ font-weight: 500;
40
+ letter-spacing: 0.01em;
41
+ cursor: pointer;
42
+ display: flex;
43
+ flex-direction: column;
44
+ align-items: center;
45
+ justify-content: center;
46
+ gap: 4px;
47
+ padding: 6px 4px;
48
+ max-width: 100%;
49
+ transition:
50
+ background var(--pincel-transition),
51
+ color var(--pincel-transition);
52
+ }
53
+ button:hover {
54
+ color: var(--pincel-color-fg);
55
+ background: var(--pincel-color-surface-2);
56
+ }
57
+ button[aria-pressed='true'] {
58
+ color: var(--pincel-color-accent);
59
+ background: var(--pincel-color-accent-soft, var(--pincel-color-surface-2));
60
+ }
61
+ .icon {
62
+ font-size: 20px;
63
+ line-height: 1;
64
+ width: 28px;
65
+ height: 28px;
66
+ display: grid;
67
+ place-items: center;
68
+ border-radius: 8px;
69
+ }
70
+ button[aria-pressed='true'] .icon {
71
+ background: var(--pincel-color-accent);
72
+ color: var(--pincel-color-accent-fg);
73
+ }
74
+ .label {
75
+ max-width: 100%;
76
+ overflow: hidden;
77
+ text-overflow: ellipsis;
78
+ white-space: nowrap;
79
+ }
80
+ `,
81
+ ]; }
82
+ static { this.properties = {
83
+ tools: { attribute: false },
84
+ active: { type: String },
85
+ orientation: { type: String, reflect: true },
86
+ t: { attribute: false },
87
+ }; }
88
+ constructor() {
89
+ super();
90
+ this.onKeydown = (e) => {
91
+ const keys = this.orientation === 'vertical' ? ['ArrowUp', 'ArrowDown'] : ['ArrowLeft', 'ArrowRight'];
92
+ const dir = e.key === keys[0] ? -1 : e.key === keys[1] ? 1 : 0;
93
+ if (dir === 0)
94
+ return;
95
+ e.preventDefault();
96
+ const idx = Math.max(0, this.tools.findIndex((t) => t.id === this.active));
97
+ const next = this.tools[(idx + dir + this.tools.length) % this.tools.length];
98
+ if (next) {
99
+ this.select(next.id);
100
+ this.updateComplete.then(() => this.renderRoot.querySelector(`[data-tool="${next.id}"]`)?.focus());
101
+ }
102
+ };
103
+ this.tools = [];
104
+ this.active = null;
105
+ this.orientation = 'horizontal';
106
+ this.t = (k) => k;
107
+ }
108
+ render() {
109
+ return html `<div class="tools" role="toolbar" aria-orientation=${this.orientation} @keydown=${this.onKeydown}>
110
+ ${this.tools.map((tool, i) => html `<button
111
+ part="tool"
112
+ type="button"
113
+ data-tool=${tool.id}
114
+ aria-pressed=${this.active === tool.id ? 'true' : 'false'}
115
+ tabindex=${this.active === tool.id || (this.active === null && i === 0) ? 0 : -1}
116
+ @click=${() => this.select(tool.id)}
117
+ >
118
+ <span class="icon" aria-hidden="true">${tool.icon}</span>
119
+ <span class="label">${this.t(tool.label)}</span>
120
+ </button>`)}
121
+ </div>`;
122
+ }
123
+ select(id) {
124
+ this.dispatchEvent(new CustomEvent('tool-select', { detail: id, bubbles: true, composed: true }));
125
+ }
126
+ }
127
+ //# sourceMappingURL=pincel-toolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pincel-toolbar.js","sourceRoot":"","sources":["../../src/components/pincel-toolbar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class SealpixelButton extends LitElement {
3
+ static styles: import("lit").CSSResult[];
4
+ static properties: {
5
+ disabled: {
6
+ type: BooleanConstructor;
7
+ reflect: boolean;
8
+ };
9
+ pressed: {
10
+ type: BooleanConstructor;
11
+ reflect: boolean;
12
+ };
13
+ variant: {
14
+ type: StringConstructor;
15
+ reflect: boolean;
16
+ };
17
+ label: {
18
+ type: StringConstructor;
19
+ };
20
+ };
21
+ disabled: boolean;
22
+ pressed: boolean;
23
+ variant: 'default' | 'primary' | 'ghost';
24
+ label: string;
25
+ constructor();
26
+ render(): import("lit").TemplateResult<1>;
27
+ }
28
+ //# sourceMappingURL=sealpixel-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sealpixel-button.d.ts","sourceRoot":"","sources":["../../src/components/sealpixel-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AAG5C,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAgB,MAAM,4BAsFpB;IAEF,OAAgB,UAAU;;;;;;;;;;;;;;;;MAKxB;IAEM,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC;;IAUb,MAAM;CAYhB"}
@@ -0,0 +1,117 @@
1
+ import { css, html, LitElement } from 'lit';
2
+ import { base } from '../theme.js';
3
+ export class SealpixelButton extends LitElement {
4
+ static { this.styles = [
5
+ base,
6
+ css `
7
+ :host {
8
+ display: inline-block;
9
+ }
10
+ /*
11
+ * The fill carries the button, not an outline. On a surface two steps
12
+ * lighter than the bar a control reads on its own, and a row of six
13
+ * outlined boxes was competing with the photo above it. The border stays
14
+ * declared, transparent, so a theme can put it back and nothing shifts.
15
+ */
16
+ button {
17
+ min-width: var(--sealpixel-control-height);
18
+ min-height: var(--sealpixel-control-height);
19
+ padding: 0 calc(var(--sealpixel-space) * 1.5);
20
+ border: 1px solid transparent;
21
+ border-radius: var(--sealpixel-radius-pill);
22
+ background: var(--sealpixel-color-surface-2);
23
+ color: var(--sealpixel-color-fg);
24
+ font: inherit;
25
+ font-size: 13px;
26
+ font-weight: 500;
27
+ cursor: pointer;
28
+ display: inline-flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ gap: var(--sealpixel-space);
32
+ width: 100%;
33
+ transition:
34
+ background var(--sealpixel-transition),
35
+ border-color var(--sealpixel-transition),
36
+ color var(--sealpixel-transition),
37
+ box-shadow var(--sealpixel-duration) var(--sealpixel-ease-out),
38
+ opacity var(--sealpixel-transition),
39
+ transform var(--sealpixel-duration) var(--sealpixel-ease-spring);
40
+ }
41
+ button:hover:not(:disabled) {
42
+ background: var(--sealpixel-color-surface-3, var(--sealpixel-color-surface-2));
43
+ }
44
+ /*
45
+ * The press scales down rather than nudging the button down by a pixel.
46
+ * A translate moves the label against a static border and reads as a
47
+ * glitch on a 44 px target; the scale keeps every edge moving together.
48
+ * It also settles fast enough to finish inside a normal tap.
49
+ */
50
+ button:active:not(:disabled) {
51
+ transform: scale(0.96);
52
+ transition-duration: var(--sealpixel-duration-fast);
53
+ transition-timing-function: var(--sealpixel-ease);
54
+ }
55
+ button:disabled {
56
+ opacity: 0.45;
57
+ cursor: default;
58
+ }
59
+ :host([variant='primary']) button {
60
+ background: var(--sealpixel-color-accent);
61
+ border-color: var(--sealpixel-color-accent);
62
+ color: var(--sealpixel-color-accent-fg);
63
+ }
64
+ :host([variant='ghost']) button {
65
+ background: transparent;
66
+ border-color: transparent;
67
+ }
68
+ :host([pressed]) button {
69
+ background: var(--sealpixel-color-accent-soft, transparent);
70
+ border-color: var(--sealpixel-color-accent);
71
+ color: var(--sealpixel-color-fg);
72
+ }
73
+ /*
74
+ * A brightness filter used to do this. It repaints the whole button
75
+ * including its text and washes out a light accent, so the hover now
76
+ * lifts the button instead of bleaching it.
77
+ */
78
+ :host([variant='primary']) button {
79
+ box-shadow: var(--sealpixel-shadow-sm, none);
80
+ }
81
+ :host([variant='primary']) button:hover:not(:disabled) {
82
+ box-shadow: var(--sealpixel-shadow-raised, none);
83
+ transform: translateY(-1px);
84
+ }
85
+ :host([variant='primary']) button:active:not(:disabled) {
86
+ box-shadow: var(--sealpixel-shadow-sm, none);
87
+ transform: scale(0.96);
88
+ }
89
+ `,
90
+ ]; }
91
+ static { this.properties = {
92
+ disabled: { type: Boolean, reflect: true },
93
+ pressed: { type: Boolean, reflect: true },
94
+ variant: { type: String, reflect: true },
95
+ label: { type: String },
96
+ }; }
97
+ constructor() {
98
+ super();
99
+ this.disabled = false;
100
+ this.pressed = false;
101
+ this.variant = 'default';
102
+ this.label = '';
103
+ }
104
+ render() {
105
+ return html `<button
106
+ part="button"
107
+ type="button"
108
+ ?disabled=${this.disabled}
109
+ aria-pressed=${this.pressed ? 'true' : 'false'}
110
+ aria-label=${this.label || undefined}
111
+ title=${this.label || undefined}
112
+ >
113
+ <slot></slot>
114
+ </button>`;
115
+ }
116
+ }
117
+ //# sourceMappingURL=sealpixel-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sealpixel-button.js","sourceRoot":"","sources":["../../src/components/sealpixel-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,MAAM,OAAO,eAAgB,SAAQ,UAAU;aAC7B,WAAM,GAAG;QACvB,IAAI;QACJ,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmFF;KACF,CAAC;aAEc,eAAU,GAAG;QAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QAC1C,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QACzC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACxC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;KACxB,CAAC;IAOF;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IAClB,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;;kBAGG,IAAI,CAAC,QAAQ;qBACV,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;mBACjC,IAAI,CAAC,KAAK,IAAI,SAAS;cAC5B,IAAI,CAAC,KAAK,IAAI,SAAS;;;cAGvB,CAAC;IACb,CAAC"}