@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,91 @@
1
+ import { RESIZE_DEFAULT_OPTIONS } from '@sealpixel/plugins';
2
+ import { html, nothing } from 'lit';
3
+ import { icons } from '../icons.js';
4
+ import { opId } from './finetune.js';
5
+ /** Whether the two dimensions move together. Kept across panel renders. */
6
+ let linked = true;
7
+ export const resizeTool = {
8
+ id: 'resize',
9
+ icon: icons.resize,
10
+ label: 'tool.resize',
11
+ panel: (ctx) => {
12
+ const target = ctx.document.resize.target;
13
+ const options = ctx.options('resize') ?? RESIZE_DEFAULT_OPTIONS;
14
+ const commit = (patch) => ctx.dispatch({
15
+ type: 'resize.set',
16
+ id: opId(),
17
+ ...(target === null ? { fit: options.defaultFit } : {}),
18
+ ...patch,
19
+ });
20
+ const num = (e) => {
21
+ const v = e.target.value.trim();
22
+ return v === '' ? null : Math.max(1, Math.round(Number(v)));
23
+ };
24
+ const src = ctx.state.source;
25
+ const ratio = src && src.width > 0 ? src.height / src.width : 1;
26
+ /**
27
+ * With the link closed the two fields are one measurement: typing either
28
+ * side writes both, so the log carries the size that will be rendered
29
+ * rather than one number and a rule for finding the other.
30
+ */
31
+ const setWidth = (w) => commit(linked && w !== null
32
+ ? { width: w, height: Math.max(1, Math.round(w * ratio)) }
33
+ : { width: w });
34
+ const setHeight = (h) => commit(linked && h !== null
35
+ ? { width: Math.max(1, Math.round(h / ratio)), height: h }
36
+ : { height: h });
37
+ // The resting value is the source's own size, so a field never sits empty
38
+ // saying nothing about what will come out.
39
+ const shownWidth = target?.width ?? src?.width ?? null;
40
+ const shownHeight = target?.height ?? src?.height ?? null;
41
+ const derived = (own) => (own == null ? 'derived' : '');
42
+ return html `
43
+ <div class="rows">
44
+ <div class="field">
45
+ <span>${ctx.t('resize.size')}</span>
46
+ <div class="dims">
47
+ <input class=${derived(target?.width)} data-field="width" type="number" min="1" max=${options.max?.width ?? nothing} inputmode="numeric" aria-label=${ctx.t('resize.width')} .value=${shownWidth?.toString() ?? ''} @change=${(e) => setWidth(num(e))} />
48
+ <sealpixel-button
49
+ variant="ghost"
50
+ data-action="link"
51
+ ?pressed=${linked}
52
+ .label=${ctx.t(linked ? 'resize.linked' : 'resize.unlinked')}
53
+ @click=${() => {
54
+ linked = !linked;
55
+ ctx.refresh();
56
+ }}
57
+ >${linked ? icons.link : icons.linkOff}</sealpixel-button
58
+ >
59
+ <input class=${derived(target?.height)} data-field="height" type="number" min="1" max=${options.max?.height ?? nothing} inputmode="numeric" aria-label=${ctx.t('resize.height')} .value=${shownHeight?.toString() ?? ''} @change=${(e) => setHeight(num(e))} />
60
+ </div>
61
+ </div>
62
+ ${
63
+ // A closed link never squeezes the image, so there is nothing for a
64
+ // fit mode to decide.
65
+ linked
66
+ ? nothing
67
+ : html `<label class="field">
68
+ <span>${ctx.t('resize.fit')}</span>
69
+ <select data-field="fit" .value=${target?.fit ?? options.defaultFit} @change=${(e) => commit({ fit: e.target.value })}>
70
+ ${options.fits.map((f) => html `<option value=${f} ?selected=${(target?.fit ?? options.defaultFit) === f}>${ctx.t(`resize.fit.${f}`)}</option>`)}
71
+ </select>
72
+ </label>`}
73
+ ${options.upscale
74
+ ? html `<label class="field check">
75
+ <input data-field="upscale" type="checkbox" .checked=${target?.upscale ?? false} @change=${(e) => commit({ upscale: e.target.checked })} />
76
+ <span>${ctx.t('resize.upscale')}</span>
77
+ </label>`
78
+ : nothing}
79
+ <sealpixel-button variant="ghost" data-action="reset" ?disabled=${target === null} .label=${ctx.t('resize.clear')} @click=${() => ctx.dispatch({ type: 'resize.clear', id: opId() })}>
80
+ ${ctx.t('resize.clear')}
81
+ </sealpixel-button>
82
+ </div>
83
+ ${options.presets.length > 0
84
+ ? html `<div class="strip choice" role="group" aria-label=${ctx.t('resize.presets')}>
85
+ ${options.presets.map((p) => html `<sealpixel-button data-preset=${p.label} variant="ghost" ?pressed=${target?.width === (p.width ?? null) && target?.height === (p.height ?? null)} @click=${() => commit({ width: p.width ?? null, height: p.height ?? null })}>${p.label}</sealpixel-button>`)}
86
+ </div>`
87
+ : nothing}
88
+ `;
89
+ },
90
+ };
91
+ //# sourceMappingURL=resize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize.js","sourceRoot":"","sources":["../../src/tools/resize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { UiTool } from '../tool.js';
2
+ /**
3
+ * Stickers live in crop space, so the normal (cropped) preview is the right
4
+ * stage. Assets come from the plugin's declarations or from an upload, which
5
+ * is registered on the session and recorded in the log.
6
+ */
7
+ export declare const stickerTool: UiTool;
8
+ //# sourceMappingURL=sticker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sticker.d.ts","sourceRoot":"","sources":["../../src/tools/sticker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAyBxD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,MA2JzB,CAAC"}
@@ -0,0 +1,156 @@
1
+ import { STICKER_DEFAULT_OPTIONS } from '@sealpixel/plugins';
2
+ import { html, nothing, svg } from 'lit';
3
+ import { icons } from '../icons.js';
4
+ import { deleteHandle, toPx } from './delete-handle.js';
5
+ import { opId } from './finetune.js';
6
+ const state = {
7
+ selected: null,
8
+ drag: null,
9
+ };
10
+ /**
11
+ * Stickers live in crop space, so the normal (cropped) preview is the right
12
+ * stage. Assets come from the plugin's declarations or from an upload, which
13
+ * is registered on the session and recorded in the log.
14
+ */
15
+ export const stickerTool = {
16
+ id: 'sticker',
17
+ icon: icons.sticker,
18
+ label: 'tool.sticker',
19
+ deactivate: () => {
20
+ state.selected = null;
21
+ state.drag = null;
22
+ },
23
+ panel: (ctx) => {
24
+ const doc = ctx.document.sticker;
25
+ const options = ctx.options('sticker') ?? STICKER_DEFAULT_OPTIONS;
26
+ const declared = options.library.length > 0
27
+ ? options.library
28
+ : (ctx.session.registry.byId.get('sticker')?.assets ?? []);
29
+ const uploaded = options.upload ? (ctx.state.history.log.assets ?? []) : [];
30
+ const full = options.max !== null && doc.items.length >= options.max;
31
+ const labelOf = (a) => a.label ?? a.id.replace(/^sticker\./, '');
32
+ const sel = doc.items.find((i) => i.id === state.selected) ?? null;
33
+ const add = (asset) => {
34
+ const id = opId();
35
+ ctx.dispatch({
36
+ type: 'sticker.add',
37
+ id,
38
+ asset,
39
+ rect: { x: 0.35, y: 0.35, width: 0.3, height: 0.3 },
40
+ });
41
+ state.selected = id;
42
+ };
43
+ const update = (patch) => sel && ctx.dispatch({ type: 'sticker.update', id: opId(), itemId: sel.id, ...patch });
44
+ const upload = async (e) => {
45
+ const file = e.target.files?.[0];
46
+ if (!file)
47
+ return;
48
+ const bytes = new Uint8Array(await file.arrayBuffer());
49
+ const decl = await ctx.session.addAsset(bytes, {
50
+ id: `sticker.${file.name
51
+ .replace(/\.[^.]+$/, '')
52
+ .replace(/[^a-z0-9-]/gi, '-')
53
+ .toLowerCase()}`,
54
+ });
55
+ add(decl.id);
56
+ };
57
+ return html `
58
+ ${options.upload
59
+ ? html `<label class="field">
60
+ <span>${ctx.t('sticker.upload')}</span>
61
+ <input data-field="upload" type="file" accept="image/png,image/jpeg,image/webp" ?disabled=${full} @change=${upload} />
62
+ </label>`
63
+ : nothing}
64
+ ${declared.length + uploaded.length > 0
65
+ ? html `<div class="grid choice" role="list" aria-label=${ctx.t('sticker.library')}>
66
+ ${[...declared, ...uploaded].map((a) => html `<sealpixel-button role="listitem" data-asset=${a.id} ?disabled=${full} @click=${() => add(a.id)}>${labelOf(a)}</sealpixel-button>`)}
67
+ </div>`
68
+ : html `<p class="hint">${ctx.t('sticker.hint.empty')}</p>`}
69
+ ${sel
70
+ ? html `
71
+ <sealpixel-slider data-param="rotation" .label=${ctx.t('sticker.rotation')} .value=${Number(((sel.rotation * 180) / Math.PI).toFixed(1))} .min=${-180} .max=${180} .step=${1} .format=${(v) => `${v.toFixed(0)}°`} @commit=${(e) => update({ rotation: (e.detail * Math.PI) / 180 })}></sealpixel-slider>
72
+ <sealpixel-slider data-param="opacity" .label=${ctx.t('sticker.opacity')} .value=${sel.opacity} .min=${0} .max=${1} .step=${0.01} @commit=${(e) => update({ opacity: e.detail })}></sealpixel-slider>
73
+ <div class="row">
74
+ <sealpixel-button data-action="flip-x" ?pressed=${sel.flipX} @click=${() => update({ flipX: !sel.flipX })}>⇋</sealpixel-button>
75
+ <sealpixel-button data-action="flip-y" ?pressed=${sel.flipY} @click=${() => update({ flipY: !sel.flipY })}>⇅</sealpixel-button>
76
+ </div>
77
+ `
78
+ : null}
79
+ `;
80
+ },
81
+ overlay: (ctx) => {
82
+ const doc = ctx.document.sticker;
83
+ const { width: W, height: H, zoom } = ctx.stage;
84
+ if (!W || !H)
85
+ return svg ``;
86
+ const sw = 1.5 / zoom;
87
+ const hr = 7 / zoom;
88
+ const toN = (e) => {
89
+ const p = ctx.stage.toImage(e.clientX, e.clientY);
90
+ return [p.x / W, p.y / H];
91
+ };
92
+ const begin = (item, mode) => (e) => {
93
+ e.stopPropagation();
94
+ e.preventDefault();
95
+ state.selected = item.id;
96
+ const start = toN(e);
97
+ state.drag = { id: item.id, rect: item.rect, mode, start };
98
+ const move = (ev) => {
99
+ if (!state.drag)
100
+ return;
101
+ const q = toN(ev);
102
+ const dx = q[0] - start[0];
103
+ const dy = q[1] - start[1];
104
+ state.drag.rect =
105
+ mode === 'move'
106
+ ? { ...item.rect, x: item.rect.x + dx, y: item.rect.y + dy }
107
+ : {
108
+ ...item.rect,
109
+ width: Math.max(0.02, item.rect.width + dx),
110
+ height: Math.max(0.02, item.rect.height + dy),
111
+ };
112
+ ctx.refresh();
113
+ };
114
+ const up = () => {
115
+ window.removeEventListener('pointermove', move);
116
+ window.removeEventListener('pointerup', up);
117
+ window.removeEventListener('pointercancel', up);
118
+ const d = state.drag;
119
+ state.drag = null;
120
+ if (d && JSON.stringify(d.rect) !== JSON.stringify(item.rect)) {
121
+ ctx.dispatch({ type: 'sticker.update', id: opId(), itemId: item.id, rect: d.rect });
122
+ }
123
+ ctx.refresh();
124
+ };
125
+ window.addEventListener('pointermove', move);
126
+ window.addEventListener('pointerup', up);
127
+ window.addEventListener('pointercancel', up);
128
+ };
129
+ const selectedItem = doc.items.find((i) => i.id === state.selected) ?? null;
130
+ return svg `
131
+ <rect data-interactive x="0" y="0" width=${W} height=${H} fill="transparent" @pointerdown=${(e) => {
132
+ e.stopPropagation();
133
+ state.selected = null;
134
+ ctx.refresh();
135
+ }} />
136
+ ${doc.items.map((item) => {
137
+ const r = state.drag?.id === item.id ? state.drag.rect : item.rect;
138
+ const selected = state.selected === item.id;
139
+ const cx = (r.x + r.width / 2) * W;
140
+ const cy = (r.y + r.height / 2) * H;
141
+ const deg = (item.rotation * 180) / Math.PI;
142
+ return svg `<g transform=${`rotate(${deg} ${cx} ${cy})`}>
143
+ <rect data-interactive data-item=${item.id} x=${r.x * W} y=${r.y * H} width=${r.width * W} height=${r.height * H} fill="rgba(255,255,255,0.001)" stroke=${selected ? 'var(--sealpixel-color-accent)' : 'rgba(255,255,255,0.6)'} stroke-width=${sw} stroke-dasharray=${selected ? 'none' : `${4 / zoom} ${3 / zoom}`} style="cursor:move" @pointerdown=${begin(item, 'move')} />
144
+ ${selected ? svg `<circle data-interactive data-handle="scale" cx=${(r.x + r.width) * W} cy=${(r.y + r.height) * H} r=${hr} fill="white" stroke="var(--sealpixel-color-accent)" stroke-width=${sw} style="cursor:nwse-resize" @pointerdown=${begin(item, 'scale')} />` : null}
145
+ </g>`;
146
+ })}
147
+ ${selectedItem
148
+ ? deleteHandle(toPx(state.drag?.id === selectedItem.id ? state.drag.rect : selectedItem.rect, W, H), ctx.stage, ctx.t('sticker.delete'), () => {
149
+ state.selected = null;
150
+ ctx.dispatch({ type: 'sticker.remove', id: opId(), itemId: selectedItem.id });
151
+ })
152
+ : nothing}
153
+ `;
154
+ },
155
+ };
156
+ //# sourceMappingURL=sticker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sticker.js","sourceRoot":"","sources":["../../src/tools/sticker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { UiTool } from '../tool.js';
2
+ export declare const watermarkTool: UiTool;
3
+ //# sourceMappingURL=watermark.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watermark.d.ts","sourceRoot":"","sources":["../../src/tools/watermark.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAkCxD,eAAO,MAAM,aAAa,EAAE,MAkF3B,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { WATERMARK_DEFAULT_OPTIONS } from '@sealpixel/plugins';
2
+ import { html, nothing } from 'lit';
3
+ import { icons } from '../icons.js';
4
+ import { opId } from './finetune.js';
5
+ const ANCHORS = ['tl', 'tc', 'tr', 'cl', 'c', 'cr', 'bl', 'bc', 'br'];
6
+ const hex = (c) => `#${[c[0], c[1], c[2]]
7
+ .map((v) => Math.round(v * 255)
8
+ .toString(16)
9
+ .padStart(2, '0'))
10
+ .join('')}`;
11
+ const fromHex = (h, a = 1) => [
12
+ Number.parseInt(h.slice(1, 3), 16) / 255,
13
+ Number.parseInt(h.slice(3, 5), 16) / 255,
14
+ Number.parseInt(h.slice(5, 7), 16) / 255,
15
+ a,
16
+ ];
17
+ export const watermarkTool = {
18
+ id: 'watermark',
19
+ icon: icons.watermark,
20
+ label: 'tool.watermark',
21
+ panel: (ctx) => {
22
+ const wm = ctx.document.watermark.watermark;
23
+ const set = (patch) => ctx.dispatch({ type: 'watermark.set', id: opId(), ...patch });
24
+ const text = wm?.source.kind === 'text' ? wm.source : null;
25
+ const options = ctx.options('watermark') ?? WATERMARK_DEFAULT_OPTIONS;
26
+ const declared = options.image
27
+ ? [
28
+ ...(ctx.session.registry.byId.get('watermark')?.assets ?? []),
29
+ ...(ctx.session.registry.byId.get('sticker')?.assets ?? []),
30
+ ...(ctx.state.history.log.assets ?? []),
31
+ ]
32
+ : [];
33
+ const fonts = ctx.session.registry.byId.get('annotate')?.assets ?? [];
34
+ const defaultFont = fonts[0]?.id ?? 'font.roboto';
35
+ const d = options.defaults;
36
+ const fresh = wm === null
37
+ ? {
38
+ ...(d.anchor ? { anchor: d.anchor } : {}),
39
+ ...(d.margin !== undefined ? { margin: d.margin } : {}),
40
+ ...(d.scale !== undefined ? { scale: d.scale } : {}),
41
+ ...(d.opacity !== undefined ? { opacity: d.opacity } : {}),
42
+ ...(d.tile !== undefined ? { tile: d.tile } : {}),
43
+ }
44
+ : {};
45
+ const anchors = ANCHORS.filter((a) => options.anchors.includes(a));
46
+ if (options.lock) {
47
+ return html `<p class="hint" data-locked>${ctx.t('watermark.locked')}</p>`;
48
+ }
49
+ return html `
50
+ <div class="row choice">
51
+ ${options.text
52
+ ? html `<sealpixel-button data-source="text" ?pressed=${text !== null} @click=${() => set({ ...fresh, source: { kind: 'text', text: text?.text ?? ctx.t('watermark.defaultText'), font: text?.font ?? defaultFont, color: text?.color ?? [1, 1, 1, 1] } })}>${ctx.t('watermark.text')}</sealpixel-button>`
53
+ : nothing}
54
+ ${declared.map((a) => html `<sealpixel-button data-source=${a.id} ?pressed=${wm?.source.kind === 'asset' && wm.source.asset === a.id} @click=${() => set({ ...fresh, source: { kind: 'asset', asset: a.id } })}>${a.label ?? a.id.replace(/^(sticker|asset|watermark)\./, '')}</sealpixel-button>`)}
55
+ ${wm ? html `<sealpixel-button data-action="clear" variant="ghost" @click=${() => ctx.dispatch({ type: 'watermark.clear', id: opId() })}>${ctx.t('watermark.clear')}</sealpixel-button>` : null}
56
+ </div>
57
+ ${wm
58
+ ? html `
59
+ <div class="rows">
60
+ ${text
61
+ ? html `<label class="field"><span>${ctx.t('watermark.textValue')}</span><input data-field="text" type="text" .value=${text.text} @change=${(e) => set({ source: { ...text, text: e.target.value || ' ' } })} /></label>
62
+ <label class="field"><span>${ctx.t('watermark.color')}</span><input data-field="color" type="color" .value=${hex(text.color)} @change=${(e) => set({ source: { ...text, color: fromHex(e.target.value) } })} /></label>`
63
+ : null}
64
+ <label class="field">
65
+ <span>${ctx.t('watermark.anchor')}</span>
66
+ <select
67
+ data-field="anchor"
68
+ ?disabled=${wm.tile !== null}
69
+ @change=${(e) => set({ anchor: e.target.value })}
70
+ >
71
+ ${anchors.map((a) => html `<option data-anchor=${a} value=${a} ?selected=${wm.anchor === a}>${ANCHOR_GLYPH[a]} ${ctx.t(`watermark.anchor.${a}`)}</option>`)}
72
+ </select>
73
+ </label>
74
+ <sealpixel-slider data-param="scale" .label=${ctx.t('watermark.scale')} .value=${wm.scale} .min=${options.scaleRange.min} .max=${options.scaleRange.max} .step=${options.scaleRange.step} .format=${(v) => `${Math.round(v * 100)}%`} @commit=${(e) => set({ scale: e.detail })}></sealpixel-slider>
75
+ ${
76
+ // Tiling repeats the mark across the image, so there is no edge
77
+ // to keep a margin from; the gap between repeats replaces it.
78
+ wm.tile
79
+ ? html `<sealpixel-slider data-param="tile-rotation" .label=${ctx.t('watermark.tileRotation')} .value=${Number(((wm.tile.rotation * 180) / Math.PI).toFixed(0))} .min=${-90} .max=${90} .step=${1} .format=${(v) => `${v.toFixed(0)}°`} @commit=${(e) => set({ tile: { ...wm.tile, rotation: (e.detail * Math.PI) / 180 } })}></sealpixel-slider>
80
+ <sealpixel-stepper data-param="tile-gap" .label=${ctx.t('watermark.tileGap')} .value=${wm.tile.gapX} .min=${0} .max=${400} .step=${1} unit="px" @commit=${(e) => set({ tile: { ...wm.tile, gapX: e.detail, gapY: e.detail } })}></sealpixel-stepper>`
81
+ : html `<sealpixel-stepper data-param="margin" .label=${ctx.t('watermark.margin')} .value=${wm.margin} .min=${0} .max=${200} .step=${1} unit="px" @commit=${(e) => set({ margin: e.detail })}></sealpixel-stepper>`}
82
+ <label class="field check">
83
+ <input data-field="tile" type="checkbox" .checked=${wm.tile !== null} @change=${(e) => set({ tile: e.target.checked ? { gapX: 24, gapY: 24, rotation: -0.4 } : null })} />
84
+ <span>${ctx.t('watermark.tile')}</span>
85
+ </label>
86
+ </div>`
87
+ : null}
88
+ `;
89
+ },
90
+ };
91
+ const ANCHOR_GLYPH = {
92
+ tl: '↖',
93
+ tc: '↑',
94
+ tr: '↗',
95
+ cl: '←',
96
+ c: '•',
97
+ cr: '→',
98
+ bl: '↙',
99
+ bc: '↓',
100
+ br: '↘',
101
+ };
102
+ //# sourceMappingURL=watermark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watermark.js","sourceRoot":"","sources":["../../src/tools/watermark.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Geometry } from '@sealpixel/core';
2
+ /** SVG-style affine: x' = a·x + c·y + e, y' = b·x + d·y + f. */
3
+ export type Affine = [number, number, number, number, number, number];
4
+ export declare const IDENTITY: Affine;
5
+ /** `outer ∘ inner`: applies `inner` first. */
6
+ export declare function compose(outer: Affine, inner: Affine): Affine;
7
+ export declare function apply(m: Affine, x: number, y: number): {
8
+ x: number;
9
+ y: number;
10
+ };
11
+ export declare function invert(m: Affine): Affine;
12
+ /** Uniform scale factor of the affine (√|det|): source px per preview px. */
13
+ export declare function scaleOf(m: Affine): number;
14
+ export declare function sameAffine(a: Affine | null, b: Affine | null, eps?: number): boolean;
15
+ /**
16
+ * Maps preview (proxy output) pixels of the rendered log back to logical
17
+ * source pixels, walking the stage geometry in reverse. Crop supplies its
18
+ * inverse affine, resize a scale or (with cover) a source rectangle; every
19
+ * other stage keeps its size. The stage uses it to keep the same source
20
+ * region in view when the preview switches between cropped and uncropped.
21
+ */
22
+ export declare function previewToSource(g: Geometry): Affine;
23
+ //# sourceMappingURL=view-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-mapping.d.ts","sourceRoot":"","sources":["../src/view-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,gEAAgE;AAChE,MAAM,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtE,eAAO,MAAM,QAAQ,EAAE,MAA2B,CAAC;AAEnD,8CAA8C;AAC9C,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAE/E;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CASxC;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,SAAO,GAAG,OAAO,CAGlF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAsBnD"}
@@ -0,0 +1,72 @@
1
+ export const IDENTITY = [1, 0, 0, 1, 0, 0];
2
+ /** `outer ∘ inner`: applies `inner` first. */
3
+ export function compose(outer, inner) {
4
+ const [a1, b1, c1, d1, e1, f1] = outer;
5
+ const [a2, b2, c2, d2, e2, f2] = inner;
6
+ return [
7
+ a1 * a2 + c1 * b2,
8
+ b1 * a2 + d1 * b2,
9
+ a1 * c2 + c1 * d2,
10
+ b1 * c2 + d1 * d2,
11
+ a1 * e2 + c1 * f2 + e1,
12
+ b1 * e2 + d1 * f2 + f1,
13
+ ];
14
+ }
15
+ export function apply(m, x, y) {
16
+ return { x: m[0] * x + m[2] * y + m[4], y: m[1] * x + m[3] * y + m[5] };
17
+ }
18
+ export function invert(m) {
19
+ const [a, b, c, d, e, f] = m;
20
+ const det = a * d - b * c;
21
+ if (!det)
22
+ return IDENTITY;
23
+ const ia = d / det;
24
+ const ib = -b / det;
25
+ const ic = -c / det;
26
+ const id = a / det;
27
+ return [ia, ib, ic, id, -(ia * e + ic * f), -(ib * e + id * f)];
28
+ }
29
+ /** Uniform scale factor of the affine (√|det|): source px per preview px. */
30
+ export function scaleOf(m) {
31
+ return Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2])) || 1;
32
+ }
33
+ export function sameAffine(a, b, eps = 1e-6) {
34
+ if (!a || !b)
35
+ return a === b;
36
+ return a.every((v, i) => Math.abs(v - b[i]) < eps);
37
+ }
38
+ /**
39
+ * Maps preview (proxy output) pixels of the rendered log back to logical
40
+ * source pixels, walking the stage geometry in reverse. Crop supplies its
41
+ * inverse affine, resize a scale or (with cover) a source rectangle; every
42
+ * other stage keeps its size. The stage uses it to keep the same source
43
+ * region in view when the preview switches between cropped and uncropped.
44
+ */
45
+ export function previewToSource(g) {
46
+ let m = IDENTITY;
47
+ for (const s of [...g.stages].reverse()) {
48
+ let step;
49
+ if (s.transform)
50
+ step = s.transform;
51
+ else if (s.cropRect) {
52
+ const [x, y, w, h] = s.cropRect;
53
+ step = [w / s.actualOut.width, 0, 0, h / s.actualOut.height, x, y];
54
+ }
55
+ else if (s.actualIn.width !== s.actualOut.width || s.actualIn.height !== s.actualOut.height) {
56
+ step = [
57
+ s.actualIn.width / s.actualOut.width,
58
+ 0,
59
+ 0,
60
+ s.actualIn.height / s.actualOut.height,
61
+ 0,
62
+ 0,
63
+ ];
64
+ }
65
+ else
66
+ continue;
67
+ m = compose(step, m);
68
+ }
69
+ const k = 1 / (g.scale || 1);
70
+ return compose([k, 0, 0, k, 0, 0], m);
71
+ }
72
+ //# sourceMappingURL=view-mapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-mapping.js","sourceRoot":"","sources":["../src/view-mapping.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,QAAQ,GAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAEnD,8CAA8C;AAC9C,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,KAAa;IAClD,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;IACvC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;IACvC,OAAO;QACL,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACjB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACjB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACjB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACjB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QACtB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS;IACnD,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;IACnB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACpB,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;IACnB,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAgB,EAAE,CAAgB,EAAE,GAAG,GAAG,IAAI;IACvE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,CAAC,CAAY,CAAC,GAAG,GAAG,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,CAAW;IACzC,IAAI,CAAC,GAAW,QAAQ,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QACxC,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC,CAAC,SAAS;YAAE,IAAI,GAAG,CAAC,CAAC,SAAmB,CAAC;aACzC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;YAChC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACrE,CAAC;aAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC9F,IAAI,GAAG;gBACL,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK;gBACpC,CAAC;gBACD,CAAC;gBACD,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM;gBACtC,CAAC;gBACD,CAAC;aACF,CAAC;QACJ,CAAC;;YAAM,SAAS;QAChB,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IAC7B,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@sealpixel/ui",
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Default, themeable Sealpixel editor UI as Web Components (Lit). Optional: the core is headless.",
5
+ "license": "BUSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9feet/sealpixel.git",
9
+ "directory": "packages/ui"
10
+ },
11
+ "homepage": "https://docs.sealpixel.dev",
12
+ "bugs": "https://github.com/9feet/sealpixel/issues",
13
+ "type": "module",
14
+ "sideEffects": [
15
+ "./dist/components/*.js",
16
+ "./dist/define.js"
17
+ ],
18
+ "files": [
19
+ "dist",
20
+ "themes",
21
+ "README.md"
22
+ ],
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ },
28
+ "./define": {
29
+ "types": "./dist/define.d.ts",
30
+ "default": "./dist/define.js"
31
+ },
32
+ "./locales/*": {
33
+ "default": "./dist/locales/*.js"
34
+ },
35
+ "./package.json": "./package.json",
36
+ "./themes/*": "./themes/*"
37
+ },
38
+ "dependencies": {
39
+ "lit": "^3.3.0",
40
+ "@sealpixel/core": "1.0.0-rc.0",
41
+ "@sealpixel/plugins": "1.0.0-rc.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^24.0.0",
45
+ "typescript": "^5.9.0",
46
+ "vitest": "^4.0.0",
47
+ "@sealpixel/wasm": "1.0.0-rc.0",
48
+ "@sealpixel/config": "0.0.0"
49
+ },
50
+ "scripts": {
51
+ "build": "tsc -p tsconfig.build.json",
52
+ "typecheck": "tsc -p tsconfig.json --noEmit",
53
+ "test": "vitest run"
54
+ }
55
+ }
@@ -0,0 +1,23 @@
1
+ /* Default tokens (graphite + coral). Included in the component; here for hosts that want the values as a starting point. */
2
+ sealpixel-editor {
3
+ --sealpixel-color-bg: #0f1117;
4
+ --sealpixel-color-surface: #161923;
5
+ --sealpixel-color-surface-2: #1f2330;
6
+ --sealpixel-color-surface-3: #2a2f3d;
7
+ --sealpixel-color-border: #2b3040;
8
+ --sealpixel-color-fg: #eef0f6;
9
+ --sealpixel-color-fg-muted: #a3a9b8;
10
+ --sealpixel-color-accent: #ff6f4c;
11
+ --sealpixel-color-accent-fg: #1c0d08;
12
+ --sealpixel-color-accent-soft: rgba(255, 111, 76, 0.16);
13
+ --sealpixel-color-danger: #ef5a5a;
14
+ --sealpixel-color-focus: #ff9b7e;
15
+ --sealpixel-radius: 12px;
16
+ --sealpixel-radius-sm: 8px;
17
+ --sealpixel-space: 8px;
18
+ --sealpixel-font: "Inter", system-ui, sans-serif;
19
+ --sealpixel-font-size: 14px;
20
+ --sealpixel-toolbar-size: 72px;
21
+ --sealpixel-panel-size: 112px;
22
+ --sealpixel-touch-target: 44px;
23
+ }
@@ -0,0 +1,30 @@
1
+ /* High contrast: WCAG AAA text contrast, thick focus rings, no translucency. */
2
+ sealpixel-editor {
3
+ --sealpixel-color-bg: #000000;
4
+ --sealpixel-color-surface: #000000;
5
+ --sealpixel-color-surface-2: #1a1a1a;
6
+ --sealpixel-color-surface-3: #333333;
7
+ --sealpixel-color-accent-soft: #333300;
8
+ --sealpixel-shadow: none;
9
+ --sealpixel-shadow-sm: none;
10
+ --sealpixel-shadow-raised: none;
11
+ --sealpixel-color-border: #ffffff;
12
+ --sealpixel-color-fg: #ffffff;
13
+ --sealpixel-color-fg-muted: #ffff00;
14
+ --sealpixel-color-accent: #ffff00;
15
+ --sealpixel-color-accent-fg: #000000;
16
+ --sealpixel-color-danger: #ff6666;
17
+ --sealpixel-color-focus: #00ffff;
18
+ --sealpixel-radius: 4px;
19
+ --sealpixel-radius-sm: 2px;
20
+ --sealpixel-font-size: 16px;
21
+ --sealpixel-touch-target: 48px;
22
+ --sealpixel-stage-checker-a: #333333;
23
+ --sealpixel-stage-checker-b: #000000;
24
+ color-scheme: dark;
25
+ }
26
+ sealpixel-editor *:focus-visible,
27
+ sealpixel-editor::part(button):focus-visible {
28
+ outline: 3px solid #00ffff;
29
+ outline-offset: 3px;
30
+ }