@inkandswitch/patchwork-pkg-base 0.0.53 → 0.0.55

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 (26) hide show
  1. package/package.json +1 -1
  2. package/packages/account/dist/{AccountPicker-HMEN6MEN.js → AccountPicker-HB6MDLKN.js} +390 -123
  3. package/packages/account/dist/AccountPicker-HB6MDLKN.js.map +7 -0
  4. package/packages/account/dist/{ContactAvatar-KCZOCABR.js → ContactAvatar-KM4BONY5.js} +7 -7
  5. package/packages/account/dist/ContactAvatar-KM4BONY5.js.map +7 -0
  6. package/packages/account/dist/{ContactCursor-RLXRAX65.js → ContactCursor-4FYCATG5.js} +6 -6
  7. package/packages/account/dist/ContactCursor-4FYCATG5.js.map +7 -0
  8. package/packages/account/dist/index.css +96 -15
  9. package/packages/account/dist/index.css.map +2 -2
  10. package/packages/account/dist/index.js +3 -3
  11. package/packages/codemirror-base/dist/{chunk-H5POLO74.js → chunk-AKNT5U37.js} +43 -28
  12. package/packages/codemirror-base/dist/chunk-AKNT5U37.js.map +7 -0
  13. package/packages/codemirror-base/dist/lib/codemirror.js +1 -1
  14. package/packages/codemirror-base/dist/tool.js +4 -1
  15. package/packages/codemirror-base/dist/tool.js.map +2 -2
  16. package/packages/drafts/dist/assets/{main-CCEftK7X.js → main-EEciTwbZ.js} +6 -8
  17. package/packages/drafts/dist/assets/{main-CCEftK7X.js.map → main-EEciTwbZ.js.map} +1 -1
  18. package/packages/drafts/dist/index.js +3 -3
  19. package/packages/tldraw4/dist/tool.js +3 -23
  20. package/packages/tldraw4/dist/tool.js.map +2 -2
  21. package/packages/account/dist/AccountPicker-HMEN6MEN.js.map +0 -7
  22. package/packages/account/dist/ContactAvatar-KCZOCABR.js.map +0 -7
  23. package/packages/account/dist/ContactCursor-RLXRAX65.js.map +0 -7
  24. package/packages/account/dist/chunk-3YUNEZX6.js +0 -38
  25. package/packages/account/dist/chunk-3YUNEZX6.js.map +0 -7
  26. package/packages/codemirror-base/dist/chunk-H5POLO74.js.map +0 -7
@@ -1,7 +1,3 @@
1
- import {
2
- USER_COLOR_PALETTE,
3
- parseHslColor
4
- } from "./chunk-3YUNEZX6.js";
5
1
  import {
6
2
  __commonJS,
7
3
  __toESM
@@ -2927,11 +2923,194 @@ function Button(props) {
2927
2923
  })();
2928
2924
  }
2929
2925
 
2926
+ // src/picker/ui/avatar-cropper.tsx
2927
+ var _tmpl$2 = /* @__PURE__ */ template(`<div class=modal-backdrop>`);
2928
+ var _tmpl$22 = /* @__PURE__ */ template(`<input class=cropper-zoom type=range min=1 max=4 step=0.01>`);
2929
+ var _tmpl$3 = /* @__PURE__ */ template(`<div class="modal cropper-modal"><p class=modal-title>Crop avatar</p><div class=cropper-viewport><img class=cropper-image><div class=cropper-mask></div></div><div class=modal-actions>`);
2930
+ var VIEWPORT = 260;
2931
+ var MAX_ZOOM = 4;
2932
+ function AvatarCropper(props) {
2933
+ const [natural, setNatural] = createSignal();
2934
+ const [zoom, setZoom] = createSignal(1);
2935
+ const [offset3, setOffset] = createSignal({
2936
+ x: 0,
2937
+ y: 0
2938
+ });
2939
+ const scale = () => {
2940
+ const n = natural();
2941
+ return n ? VIEWPORT / Math.min(n.w, n.h) * zoom() : 1;
2942
+ };
2943
+ const size3 = () => {
2944
+ const n = natural();
2945
+ return {
2946
+ w: n.w * scale(),
2947
+ h: n.h * scale()
2948
+ };
2949
+ };
2950
+ const clamp2 = (next) => {
2951
+ const {
2952
+ w,
2953
+ h
2954
+ } = size3();
2955
+ return {
2956
+ x: Math.min(0, Math.max(VIEWPORT - w, next.x)),
2957
+ y: Math.min(0, Math.max(VIEWPORT - h, next.y))
2958
+ };
2959
+ };
2960
+ const onLoad = (e) => {
2961
+ const img = e.currentTarget;
2962
+ setNatural({
2963
+ w: img.naturalWidth,
2964
+ h: img.naturalHeight
2965
+ });
2966
+ const s = scale();
2967
+ setOffset({
2968
+ x: (VIEWPORT - img.naturalWidth * s) / 2,
2969
+ y: (VIEWPORT - img.naturalHeight * s) / 2
2970
+ });
2971
+ };
2972
+ const onPointerDown = (e) => {
2973
+ if (!natural()) return;
2974
+ const el = e.currentTarget;
2975
+ el.setPointerCapture(e.pointerId);
2976
+ const start = {
2977
+ ...offset3(),
2978
+ px: e.clientX,
2979
+ py: e.clientY
2980
+ };
2981
+ const onMove = (move) => {
2982
+ setOffset(clamp2({
2983
+ x: start.x + move.clientX - start.px,
2984
+ y: start.y + move.clientY - start.py
2985
+ }));
2986
+ };
2987
+ const onUp = () => {
2988
+ el.removeEventListener("pointermove", onMove);
2989
+ el.removeEventListener("pointerup", onUp);
2990
+ el.removeEventListener("pointercancel", onUp);
2991
+ };
2992
+ el.addEventListener("pointermove", onMove);
2993
+ el.addEventListener("pointerup", onUp);
2994
+ el.addEventListener("pointercancel", onUp);
2995
+ };
2996
+ const setZoomAroundCenter = (next) => {
2997
+ if (!natural()) return;
2998
+ const previous = scale();
2999
+ setZoom(Math.min(MAX_ZOOM, Math.max(1, next)));
3000
+ const ratio = scale() / previous;
3001
+ const o = offset3();
3002
+ setOffset(clamp2({
3003
+ x: VIEWPORT / 2 - (VIEWPORT / 2 - o.x) * ratio,
3004
+ y: VIEWPORT / 2 - (VIEWPORT / 2 - o.y) * ratio
3005
+ }));
3006
+ };
3007
+ const onWheel = (e) => {
3008
+ e.preventDefault();
3009
+ setZoomAroundCenter(zoom() * (1 - e.deltaY / 500));
3010
+ };
3011
+ const onConfirm = () => {
3012
+ const o = offset3();
3013
+ const s = scale();
3014
+ props.onConfirm({
3015
+ x: -o.x / s,
3016
+ y: -o.y / s,
3017
+ size: VIEWPORT / s
3018
+ });
3019
+ };
3020
+ return [(() => {
3021
+ var _el$ = _tmpl$2();
3022
+ addEventListener(_el$, "click", props.onCancel, true);
3023
+ return _el$;
3024
+ })(), (() => {
3025
+ var _el$2 = _tmpl$3(), _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$7 = _el$4.nextSibling;
3026
+ _el$4.addEventListener("wheel", onWheel);
3027
+ _el$4.$$pointerdown = onPointerDown;
3028
+ _el$5.addEventListener("load", onLoad);
3029
+ setAttribute(_el$5, "draggable", false);
3030
+ insert(_el$2, createComponent(Show, {
3031
+ get when() {
3032
+ return natural();
3033
+ },
3034
+ get children() {
3035
+ var _el$6 = _tmpl$22();
3036
+ _el$6.$$input = (e) => setZoomAroundCenter(e.currentTarget.valueAsNumber);
3037
+ createRenderEffect(() => _el$6.value = zoom());
3038
+ return _el$6;
3039
+ }
3040
+ }), _el$7);
3041
+ insert(_el$7, createComponent(Button, {
3042
+ variant: "secondary",
3043
+ get onClick() {
3044
+ return props.onCancel;
3045
+ },
3046
+ children: "Cancel"
3047
+ }), null);
3048
+ insert(_el$7, createComponent(Button, {
3049
+ onClick: onConfirm,
3050
+ get disabled() {
3051
+ return !natural();
3052
+ },
3053
+ children: "Save"
3054
+ }), null);
3055
+ createRenderEffect((_p$) => {
3056
+ var _v$ = props.src, _v$2 = natural() ? {
3057
+ width: `${size3().w}px`,
3058
+ height: `${size3().h}px`,
3059
+ transform: `translate(${offset3().x}px, ${offset3().y}px)`
3060
+ } : {
3061
+ visibility: "hidden"
3062
+ };
3063
+ _v$ !== _p$.e && setAttribute(_el$5, "src", _p$.e = _v$);
3064
+ _p$.t = style(_el$5, _v$2, _p$.t);
3065
+ return _p$;
3066
+ }, {
3067
+ e: void 0,
3068
+ t: void 0
3069
+ });
3070
+ return _el$2;
3071
+ })()];
3072
+ }
3073
+ delegateEvents(["click", "pointerdown", "input"]);
3074
+
3075
+ // src/user-colors.ts
3076
+ var USER_COLOR_PALETTE = [
3077
+ { name: "Sky Blue", value: "hsl(200, 70%, 50%)" },
3078
+ { name: "Coral", value: "hsl(10, 75%, 58%)" },
3079
+ { name: "Emerald", value: "hsl(145, 70%, 45%)" },
3080
+ { name: "Violet", value: "hsl(270, 70%, 55%)" },
3081
+ { name: "Amber", value: "hsl(38, 85%, 50%)" },
3082
+ { name: "Rose", value: "hsl(350, 70%, 55%)" },
3083
+ { name: "Teal", value: "hsl(178, 70%, 45%)" },
3084
+ { name: "Indigo", value: "hsl(235, 70%, 58%)" },
3085
+ { name: "Lime", value: "hsl(85, 70%, 45%)" },
3086
+ { name: "Fuchsia", value: "hsl(310, 70%, 55%)" },
3087
+ { name: "Orange", value: "hsl(25, 80%, 52%)" },
3088
+ { name: "Cyan", value: "hsl(188, 75%, 48%)" }
3089
+ ];
3090
+ function generateColorFromString(str) {
3091
+ const hash = Math.abs(
3092
+ str.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0)
3093
+ );
3094
+ const colorIndex = hash % USER_COLOR_PALETTE.length;
3095
+ return USER_COLOR_PALETTE[colorIndex].value;
3096
+ }
3097
+ function getRandomUserColor() {
3098
+ return USER_COLOR_PALETTE[Math.floor(Math.random() * USER_COLOR_PALETTE.length)].value;
3099
+ }
3100
+ function parseHslColor(color) {
3101
+ const match = color.match(/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$/);
3102
+ if (!match) return null;
3103
+ return {
3104
+ h: parseInt(match[1], 10),
3105
+ s: parseInt(match[2], 10),
3106
+ l: parseInt(match[3], 10)
3107
+ };
3108
+ }
3109
+
2930
3110
  // src/picker/ui/color-picker.tsx
2931
- var _tmpl$2 = /* @__PURE__ */ template(`<button type=button class=color-trigger>`);
2932
- var _tmpl$22 = /* @__PURE__ */ template(`<div class=color-popup><div class=color-grid><label class="color-swatch color-swatch-custom"title="Custom color"><input type=color>`);
2933
- var _tmpl$3 = /* @__PURE__ */ template(`<svg class=icon-check viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=3 stroke-linecap=round stroke-linejoin=round><polyline points="20 6 9 17 4 12">`);
2934
- var _tmpl$4 = /* @__PURE__ */ template(`<button type=button>`);
3111
+ var _tmpl$4 = /* @__PURE__ */ template(`<div class=color-popup><div class=color-grid><label class="color-swatch color-swatch-custom"title="Custom color"><input type=color>`);
3112
+ var _tmpl$23 = /* @__PURE__ */ template(`<svg class=icon-check viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=3 stroke-linecap=round stroke-linejoin=round><polyline points="20 6 9 17 4 12">`);
3113
+ var _tmpl$32 = /* @__PURE__ */ template(`<button type=button>`);
2935
3114
  function hslToHex(hsl) {
2936
3115
  const parsed = parseHslColor(hsl);
2937
3116
  if (!parsed) return "#3b82f6";
@@ -2964,73 +3143,82 @@ function hslToHex(hsl) {
2964
3143
  const hex = (c) => Math.round(c * 255).toString(16).padStart(2, "0");
2965
3144
  return `#${hex(r)}${hex(g)}${hex(b)}`;
2966
3145
  }
2967
- function ColorPicker(props) {
2968
- const [open, setOpen] = createSignal(false);
3146
+ function ColorPopup(props) {
2969
3147
  const currentColor = () => props.value || USER_COLOR_PALETTE[0].value;
2970
3148
  const inputValue = () => {
2971
3149
  const v = currentColor();
2972
3150
  return v.startsWith("#") ? v : hslToHex(v);
2973
3151
  };
2974
- return [(() => {
2975
- var _el$ = _tmpl$2();
2976
- _el$.$$click = (e) => {
2977
- e.stopPropagation();
2978
- setOpen(!open());
2979
- };
2980
- createRenderEffect((_$p) => setStyleProperty(_el$, "background-color", currentColor()));
3152
+ return (() => {
3153
+ var _el$ = _tmpl$4(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild;
3154
+ var _ref$ = props.ref;
3155
+ typeof _ref$ === "function" ? use(_ref$, _el$) : props.ref = _el$;
3156
+ insert(_el$2, createComponent(For, {
3157
+ get each() {
3158
+ return [...USER_COLOR_PALETTE];
3159
+ },
3160
+ children: (color) => (() => {
3161
+ var _el$5 = _tmpl$32();
3162
+ _el$5.$$click = () => {
3163
+ props.onChange(color.value);
3164
+ props.onClose();
3165
+ };
3166
+ insert(_el$5, createComponent(Show, {
3167
+ get when() {
3168
+ return props.value === color.value;
3169
+ },
3170
+ get children() {
3171
+ return _tmpl$23();
3172
+ }
3173
+ }));
3174
+ createRenderEffect((_p$) => {
3175
+ var _v$ = `color-swatch${props.value === color.value ? " selected" : ""}`, _v$2 = color.value, _v$3 = color.name;
3176
+ _v$ !== _p$.e && className(_el$5, _p$.e = _v$);
3177
+ _v$2 !== _p$.t && setStyleProperty(_el$5, "background-color", _p$.t = _v$2);
3178
+ _v$3 !== _p$.a && setAttribute(_el$5, "title", _p$.a = _v$3);
3179
+ return _p$;
3180
+ }, {
3181
+ e: void 0,
3182
+ t: void 0,
3183
+ a: void 0
3184
+ });
3185
+ return _el$5;
3186
+ })()
3187
+ }), _el$3);
3188
+ _el$4.$$input = (e) => props.onChange(e.currentTarget.value);
3189
+ createRenderEffect(() => _el$4.value = inputValue());
2981
3190
  return _el$;
2982
- })(), createComponent(Show, {
2983
- get when() {
2984
- return open();
2985
- },
2986
- get children() {
2987
- var _el$2 = _tmpl$22(), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild;
2988
- insert(_el$3, createComponent(For, {
2989
- get each() {
2990
- return [...USER_COLOR_PALETTE];
2991
- },
2992
- children: (color) => (() => {
2993
- var _el$6 = _tmpl$4();
2994
- _el$6.$$click = () => {
2995
- props.onChange(color.value);
2996
- setOpen(false);
2997
- };
2998
- insert(_el$6, createComponent(Show, {
2999
- get when() {
3000
- return props.value === color.value;
3001
- },
3002
- get children() {
3003
- return _tmpl$3();
3004
- }
3005
- }));
3006
- createRenderEffect((_p$) => {
3007
- var _v$ = `color-swatch${props.value === color.value ? " selected" : ""}`, _v$2 = color.value, _v$3 = color.name;
3008
- _v$ !== _p$.e && className(_el$6, _p$.e = _v$);
3009
- _v$2 !== _p$.t && setStyleProperty(_el$6, "background-color", _p$.t = _v$2);
3010
- _v$3 !== _p$.a && setAttribute(_el$6, "title", _p$.a = _v$3);
3011
- return _p$;
3012
- }, {
3013
- e: void 0,
3014
- t: void 0,
3015
- a: void 0
3016
- });
3017
- return _el$6;
3018
- })()
3019
- }), _el$4);
3020
- _el$5.$$input = (e) => props.onChange(e.currentTarget.value);
3021
- createRenderEffect(() => _el$5.value = inputValue());
3022
- return _el$2;
3023
- }
3024
- })];
3191
+ })();
3192
+ }
3193
+ delegateEvents(["input", "click"]);
3194
+
3195
+ // src/picker/ui/presence-cursor.tsx
3196
+ var _tmpl$5 = /* @__PURE__ */ template(`<button type=button class=presence-cursor><svg class=presence-cursor-arrow viewBox="11 7 14 21"><g fill=#fff><path d="m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z"></path><path d="m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z"></path></g><g><path d="m13 10.814v11.188l2.969-2.866.428-.139h4.768z"></path><path d="m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z"></path></g></svg><span class=presence-nametag>`);
3197
+ function PresenceCursor(props) {
3198
+ const [local, rest] = splitProps(props, ["color", "name"]);
3199
+ return (() => {
3200
+ var _el$ = _tmpl$5(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$2.nextSibling;
3201
+ spread(_el$, rest, false, true);
3202
+ insert(_el$5, () => local.name);
3203
+ createRenderEffect((_p$) => {
3204
+ var _v$ = local.color, _v$2 = local.color;
3205
+ _v$ !== _p$.e && setAttribute(_el$4, "fill", _p$.e = _v$);
3206
+ _v$2 !== _p$.t && setStyleProperty(_el$5, "background-color", _p$.t = _v$2);
3207
+ return _p$;
3208
+ }, {
3209
+ e: void 0,
3210
+ t: void 0
3211
+ });
3212
+ return _el$;
3213
+ })();
3025
3214
  }
3026
- delegateEvents(["click", "input"]);
3027
3215
 
3028
3216
  // src/picker/ui/input.tsx
3029
- var _tmpl$5 = /* @__PURE__ */ template(`<input>`);
3217
+ var _tmpl$6 = /* @__PURE__ */ template(`<input>`);
3030
3218
  function Input(props) {
3031
3219
  const [local, rest] = splitProps(props, ["class", "type"]);
3032
3220
  return (() => {
3033
- var _el$ = _tmpl$5();
3221
+ var _el$ = _tmpl$6();
3034
3222
  spread(_el$, mergeProps({
3035
3223
  get type() {
3036
3224
  return local.type;
@@ -3044,11 +3232,11 @@ function Input(props) {
3044
3232
  }
3045
3233
 
3046
3234
  // src/picker/ui/label.tsx
3047
- var _tmpl$6 = /* @__PURE__ */ template(`<label>`);
3235
+ var _tmpl$7 = /* @__PURE__ */ template(`<label>`);
3048
3236
  function Label(props) {
3049
3237
  const [local, rest] = splitProps(props, ["class", "children"]);
3050
3238
  return (() => {
3051
- var _el$ = _tmpl$6();
3239
+ var _el$ = _tmpl$7();
3052
3240
  spread(_el$, mergeProps({
3053
3241
  get ["class"]() {
3054
3242
  return `label${local.class ? " " + local.class : ""}`;
@@ -7130,7 +7318,7 @@ function usePopperContext() {
7130
7318
  }
7131
7319
  return context;
7132
7320
  }
7133
- var _tmpl$7 = /* @__PURE__ */ template(`<svg display="block" viewBox="0 0 30 30" style="transform:scale(1.02)"><g><path fill="none" d="M23,27.8c1.1,1.2,3.4,2.2,5,2.2h2H0h2c1.7,0,3.9-1,5-2.2l6.6-7.2c0.7-0.8,2-0.8,2.7,0L23,27.8L23,27.8z"></path><path stroke="none" d="M23,27.8c1.1,1.2,3.4,2.2,5,2.2h2H0h2c1.7,0,3.9-1,5-2.2l6.6-7.2c0.7-0.8,2-0.8,2.7,0L23,27.8L23,27.8z">`);
7321
+ var _tmpl$8 = /* @__PURE__ */ template(`<svg display="block" viewBox="0 0 30 30" style="transform:scale(1.02)"><g><path fill="none" d="M23,27.8c1.1,1.2,3.4,2.2,5,2.2h2H0h2c1.7,0,3.9-1,5-2.2l6.6-7.2c0.7-0.8,2-0.8,2.7,0L23,27.8L23,27.8z"></path><path stroke="none" d="M23,27.8c1.1,1.2,3.4,2.2,5,2.2h2H0h2c1.7,0,3.9-1,5-2.2l6.6-7.2c0.7-0.8,2-0.8,2.7,0L23,27.8L23,27.8z">`);
7134
7322
  var DEFAULT_SIZE = 30;
7135
7323
  var HALF_DEFAULT_SIZE = DEFAULT_SIZE / 2;
7136
7324
  var ROTATION_DEG = {
@@ -7178,7 +7366,7 @@ function PopperArrow(props) {
7178
7366
  }
7179
7367
  }, others, {
7180
7368
  get children() {
7181
- const _el$ = _tmpl$7(), _el$2 = _el$.firstChild;
7369
+ const _el$ = _tmpl$8(), _el$2 = _el$.firstChild;
7182
7370
  createRenderEffect(() => setAttribute(_el$2, "transform", rotate()));
7183
7371
  return _el$;
7184
7372
  }
@@ -8254,15 +8442,15 @@ var TooltipTrigger2 = Tooltip.Trigger;
8254
8442
  var TooltipContent2 = Tooltip.Content;
8255
8443
 
8256
8444
  // src/picker/AccountPicker.tsx
8257
- var _tmpl$8 = /* @__PURE__ */ template(`<div class=field-group>`);
8258
- var _tmpl$23 = /* @__PURE__ */ template(`<div>Not a valid account token, try copy-pasting again.`);
8259
- var _tmpl$32 = /* @__PURE__ */ template(`<div class=loading-text>Looking up account...`);
8445
+ var _tmpl$9 = /* @__PURE__ */ template(`<div class=field-group>`);
8446
+ var _tmpl$24 = /* @__PURE__ */ template(`<div>Not a valid account token, try copy-pasting again.`);
8447
+ var _tmpl$33 = /* @__PURE__ */ template(`<div class=loading-text>Looking up account...`);
8260
8448
  var _tmpl$42 = /* @__PURE__ */ template(`<div>Account not found`);
8261
8449
  var _tmpl$52 = /* @__PURE__ */ template(`<form class=field-group><p class=hint>Paste your account token to log in. You can find it in account settings on any device where you're signed in.</p><div class=input-row></div><div class=error-text>`);
8262
8450
  var _tmpl$62 = /* @__PURE__ */ template(`<input type=file accept=image/* class=sr-only>`);
8263
- var _tmpl$72 = /* @__PURE__ */ template(`<button type=button class=avatar-button title="Click to change avatar"><patchwork-view tool-id=contact>`, true, false, false);
8264
- var _tmpl$82 = /* @__PURE__ */ template(`<div class=profile-header><div class=avatar-area>`);
8265
- var _tmpl$9 = /* @__PURE__ */ template(`<p>Copied`);
8451
+ var _tmpl$72 = /* @__PURE__ */ template(`<button type=button class=avatar-button title="Change avatar"><patchwork-view tool-id=contact>`, true, false, false);
8452
+ var _tmpl$82 = /* @__PURE__ */ template(`<div class=profile-header><div class=identity><div class=presence-slot>`);
8453
+ var _tmpl$92 = /* @__PURE__ */ template(`<p>Copied`);
8266
8454
  var _tmpl$0 = /* @__PURE__ */ template(`<div class=actions>`);
8267
8455
  var _tmpl$1 = /* @__PURE__ */ template(`<div class=modal-backdrop>`);
8268
8456
  var _tmpl$10 = /* @__PURE__ */ template(`<div class=modal><p class=modal-title>Sign out?</p><p class=hint>Make sure you've saved your account token first.</p><div class=input-row></div><div class=modal-actions>`);
@@ -8275,6 +8463,7 @@ var AccountPicker = (props) => {
8275
8463
  const currentAccount = makeDocumentProjection(props.handle);
8276
8464
  const [self, selfHandle] = useDocument(() => currentAccount.contactUrl, props.element);
8277
8465
  let avatarInputRef;
8466
+ let colorPopupRef;
8278
8467
  const [signupName, setSignupName] = createSignal("");
8279
8468
  const [activeTab, setActiveTab] = createSignal(
8280
8469
  "signUp"
@@ -8284,6 +8473,8 @@ var AccountPicker = (props) => {
8284
8473
  const [isCopyTooltipOpen, setIsCopyTooltipOpen] = createSignal(false);
8285
8474
  const [isContactCardCopyTooltipOpen, setIsContactCardCopyTooltipOpen] = createSignal(false);
8286
8475
  const [showSignOutConfirm, setShowSignOutConfirm] = createSignal(false);
8476
+ const [showColorPopup, setShowColorPopup] = createSignal(false);
8477
+ const [pendingAvatar, setPendingAvatar] = createSignal();
8287
8478
  const [accountTokenToLogin, setAccountTokenToLogin] = createSignal("");
8288
8479
  const accountAutomergeUrlToLogin = createMemo(() => accountTokenToAutomergeUrl(accountTokenToLogin()));
8289
8480
  const [accountToLogin, accountToLoginHandle] = useDocument(accountAutomergeUrlToLogin);
@@ -8304,6 +8495,25 @@ var AccountPicker = (props) => {
8304
8495
  const s = self();
8305
8496
  return s?.type === "registered" ? s.name : "";
8306
8497
  };
8498
+ createEffect(() => {
8499
+ if (!showColorPopup()) return;
8500
+ const onPointerDown = (event) => {
8501
+ const target = event.target;
8502
+ if (colorPopupRef?.contains(target)) return;
8503
+ if (target?.closest(".presence-cursor")) return;
8504
+ setShowColorPopup(false);
8505
+ };
8506
+ const onKeyDown = (event) => {
8507
+ if (event.key === "Escape") setShowColorPopup(false);
8508
+ };
8509
+ document.addEventListener("pointerdown", onPointerDown, true);
8510
+ document.addEventListener("keydown", onKeyDown);
8511
+ onCleanup(() => {
8512
+ document.removeEventListener("pointerdown", onPointerDown, true);
8513
+ document.removeEventListener("keydown", onKeyDown);
8514
+ });
8515
+ });
8516
+ const presenceColor = () => self()?.color || "#888";
8307
8517
  const currentAccountToken = createMemo(() => {
8308
8518
  return currentAccount ? automergeUrlToAccountToken(props.handle.url, name()) : null;
8309
8519
  });
@@ -8323,20 +8533,34 @@ var AccountPicker = (props) => {
8323
8533
  contact.color = newColor;
8324
8534
  });
8325
8535
  };
8326
- const onAvatarChange = async (e) => {
8536
+ const onAvatarChange = (e) => {
8327
8537
  const target = e.target;
8328
- const s = self();
8329
- if (!currentAccount || !s || s.type !== "registered") return;
8330
8538
  const avatarFile = !target.files ? void 0 : target.files[0];
8539
+ target.value = "";
8331
8540
  if (!avatarFile) return;
8332
- const compressed = await compressAvatar(avatarFile);
8541
+ setPendingAvatar({
8542
+ file: avatarFile,
8543
+ url: URL.createObjectURL(avatarFile)
8544
+ });
8545
+ };
8546
+ const onCancelCrop = () => {
8547
+ const pending = pendingAvatar();
8548
+ if (pending) URL.revokeObjectURL(pending.url);
8549
+ setPendingAvatar(void 0);
8550
+ };
8551
+ const onCropAvatar = async (crop) => {
8552
+ const pending = pendingAvatar();
8553
+ const s = self();
8554
+ if (!pending || !currentAccount || !s || s.type !== "registered") return;
8555
+ onCancelCrop();
8556
+ const compressed = await compressAvatar(pending.file, crop);
8333
8557
  if (!compressed) return;
8334
8558
  const repo = props.element.repo;
8335
8559
  const imageHandle = await repo.create2();
8336
8560
  imageHandle.change((doc) => {
8337
8561
  doc.content = compressed.content;
8338
8562
  doc.mimeType = compressed.mimeType;
8339
- doc.name = avatarFile.name;
8563
+ doc.name = pending.file.name;
8340
8564
  doc.extension = "webp";
8341
8565
  });
8342
8566
  selfHandle()?.change((contact) => {
@@ -8347,21 +8571,28 @@ var AccountPicker = (props) => {
8347
8571
  };
8348
8572
  const onSignUp = async () => {
8349
8573
  if (!currentAccount || !signupName()) return;
8574
+ let targetContactHandle = selfHandle();
8350
8575
  if (!currentAccount.contactUrl) {
8351
8576
  const repo = props.element.repo;
8352
- const contactHandle = await repo.create2({
8577
+ targetContactHandle = await repo.create2({
8353
8578
  ["@patchwork"]: {
8354
8579
  type: "patchwork:contact"
8355
8580
  },
8356
- type: "anonymous"
8581
+ type: "anonymous",
8582
+ color: getRandomUserColor()
8357
8583
  });
8584
+ const targetContactUrl = targetContactHandle.url;
8358
8585
  props.handle.change((account) => {
8359
- account.contactUrl = contactHandle.url;
8586
+ account.contactUrl = targetContactUrl;
8360
8587
  });
8361
8588
  }
8362
- selfHandle()?.change((contact) => {
8589
+ if (!targetContactHandle) return;
8590
+ targetContactHandle.change((contact) => {
8363
8591
  contact.type = "registered";
8364
8592
  contact.name = signupName();
8593
+ if (!contact.color) {
8594
+ contact.color = generateColorFromString(targetContactHandle.url);
8595
+ }
8365
8596
  });
8366
8597
  };
8367
8598
  const onLogIn = async () => {
@@ -8431,7 +8662,7 @@ var AccountPicker = (props) => {
8431
8662
  value: "signUp",
8432
8663
  "class": "tabs-content",
8433
8664
  get children() {
8434
- var _el$2 = _tmpl$8();
8665
+ var _el$2 = _tmpl$9();
8435
8666
  insert(_el$2, createComponent(Label, {
8436
8667
  "for": "name",
8437
8668
  children: "Name"
@@ -8503,7 +8734,7 @@ var AccountPicker = (props) => {
8503
8734
  return accountTokenToLoginStatus() === "malformed";
8504
8735
  },
8505
8736
  get children() {
8506
- return _tmpl$23();
8737
+ return _tmpl$24();
8507
8738
  }
8508
8739
  }), null);
8509
8740
  insert(_el$6, createComponent(Show, {
@@ -8511,7 +8742,7 @@ var AccountPicker = (props) => {
8511
8742
  return accountTokenToLoginStatus() === "loading";
8512
8743
  },
8513
8744
  get children() {
8514
- return _tmpl$32();
8745
+ return _tmpl$33();
8515
8746
  }
8516
8747
  }), null);
8517
8748
  insert(_el$6, createComponent(Show, {
@@ -8549,7 +8780,7 @@ var AccountPicker = (props) => {
8549
8780
  use((el) => avatarInputRef = el, _el$0);
8550
8781
  return _el$0;
8551
8782
  })(), (() => {
8552
- var _el$1 = _tmpl$82(), _el$10 = _el$1.firstChild;
8783
+ var _el$1 = _tmpl$82(), _el$10 = _el$1.firstChild, _el$13 = _el$10.firstChild;
8553
8784
  insert(_el$10, createComponent(Show, {
8554
8785
  get when() {
8555
8786
  return currentAccount?.contactUrl;
@@ -8558,15 +8789,42 @@ var AccountPicker = (props) => {
8558
8789
  var _el$11 = _tmpl$72(), _el$12 = _el$11.firstChild;
8559
8790
  _el$11.$$click = () => avatarInputRef?.click();
8560
8791
  _el$12._$owner = getOwner();
8561
- createRenderEffect(() => _el$12.docUrl = currentAccount.contactUrl);
8792
+ createRenderEffect((_p$) => {
8793
+ var _v$ = `0 0 0 2px var(--account-picker-bg), 0 0 0 5px ${presenceColor()}`, _v$2 = currentAccount.contactUrl;
8794
+ _v$ !== _p$.e && setStyleProperty(_el$11, "box-shadow", _p$.e = _v$);
8795
+ _v$2 !== _p$.t && (_el$12.docUrl = _p$.t = _v$2);
8796
+ return _p$;
8797
+ }, {
8798
+ e: void 0,
8799
+ t: void 0
8800
+ });
8562
8801
  return _el$11;
8563
8802
  }
8564
- }), null);
8565
- insert(_el$10, createComponent(ColorPicker, {
8566
- get value() {
8567
- return self()?.color;
8803
+ }), _el$13);
8804
+ insert(_el$13, createComponent(PresenceCursor, {
8805
+ get color() {
8806
+ return presenceColor();
8807
+ },
8808
+ get name() {
8809
+ return name() || "You";
8568
8810
  },
8569
- onChange: onColorChange
8811
+ title: "Change presence colour",
8812
+ onClick: () => setShowColorPopup((prev) => !prev)
8813
+ }));
8814
+ insert(_el$10, createComponent(Show, {
8815
+ get when() {
8816
+ return showColorPopup();
8817
+ },
8818
+ get children() {
8819
+ return createComponent(ColorPopup, {
8820
+ ref: (el) => colorPopupRef = el,
8821
+ get value() {
8822
+ return self()?.color;
8823
+ },
8824
+ onChange: onColorChange,
8825
+ onClose: () => setShowColorPopup(false)
8826
+ });
8827
+ }
8570
8828
  }), null);
8571
8829
  insert(_el$1, createComponent(Input, {
8572
8830
  id: "name",
@@ -8579,8 +8837,8 @@ var AccountPicker = (props) => {
8579
8837
  }), null);
8580
8838
  return _el$1;
8581
8839
  })(), (() => {
8582
- var _el$13 = _tmpl$0();
8583
- insert(_el$13, createComponent(Tooltip2, {
8840
+ var _el$14 = _tmpl$0();
8841
+ insert(_el$14, createComponent(Tooltip2, {
8584
8842
  get open() {
8585
8843
  return isCopyTooltipOpen();
8586
8844
  },
@@ -8603,12 +8861,12 @@ var AccountPicker = (props) => {
8603
8861
  }), createComponent(TooltipContent2, {
8604
8862
  "class": "tooltip-content",
8605
8863
  get children() {
8606
- return _tmpl$9();
8864
+ return _tmpl$92();
8607
8865
  }
8608
8866
  })];
8609
8867
  }
8610
8868
  }), null);
8611
- insert(_el$13, createComponent(Show, {
8869
+ insert(_el$14, createComponent(Show, {
8612
8870
  get when() {
8613
8871
  return props.element.hive?.active?.contactCard;
8614
8872
  },
@@ -8636,36 +8894,47 @@ var AccountPicker = (props) => {
8636
8894
  }), createComponent(TooltipContent2, {
8637
8895
  "class": "tooltip-content",
8638
8896
  get children() {
8639
- return _tmpl$9();
8897
+ return _tmpl$92();
8640
8898
  }
8641
8899
  })];
8642
8900
  }
8643
8901
  });
8644
8902
  }
8645
8903
  }), null);
8646
- insert(_el$13, createComponent(Button, {
8904
+ insert(_el$14, createComponent(Button, {
8647
8905
  onClick: () => setShowSignOutConfirm(true),
8648
8906
  variant: "ghost",
8649
8907
  "class": "sign-out",
8650
8908
  children: "Sign out"
8651
8909
  }), null);
8652
- return _el$13;
8910
+ return _el$14;
8653
8911
  })(), createComponent(Show, {
8912
+ get when() {
8913
+ return pendingAvatar();
8914
+ },
8915
+ children: (pending) => createComponent(AvatarCropper, {
8916
+ get src() {
8917
+ return pending().url;
8918
+ },
8919
+ onCancel: onCancelCrop,
8920
+ onConfirm: onCropAvatar
8921
+ })
8922
+ }), createComponent(Show, {
8654
8923
  get when() {
8655
8924
  return showSignOutConfirm();
8656
8925
  },
8657
8926
  get children() {
8658
8927
  return [(() => {
8659
- var _el$16 = _tmpl$1();
8660
- _el$16.$$click = () => setShowSignOutConfirm(false);
8661
- return _el$16;
8928
+ var _el$17 = _tmpl$1();
8929
+ _el$17.$$click = () => setShowSignOutConfirm(false);
8930
+ return _el$17;
8662
8931
  })(), (() => {
8663
- var _el$17 = _tmpl$10(), _el$18 = _el$17.firstChild, _el$19 = _el$18.nextSibling, _el$20 = _el$19.nextSibling, _el$22 = _el$20.nextSibling;
8664
- insert(_el$17, createComponent(Label, {
8932
+ var _el$18 = _tmpl$10(), _el$19 = _el$18.firstChild, _el$20 = _el$19.nextSibling, _el$21 = _el$20.nextSibling, _el$23 = _el$21.nextSibling;
8933
+ insert(_el$18, createComponent(Label, {
8665
8934
  "for": "signOutAccountUrl",
8666
8935
  children: "Account token"
8667
- }), _el$20);
8668
- insert(_el$20, createComponent(Input, {
8936
+ }), _el$21);
8937
+ insert(_el$21, createComponent(Input, {
8669
8938
  onFocus: (e) => e.currentTarget.select(),
8670
8939
  get value() {
8671
8940
  return currentAccountToken() || "";
@@ -8677,7 +8946,7 @@ var AccountPicker = (props) => {
8677
8946
  readOnly: true,
8678
8947
  autocomplete: "off"
8679
8948
  }), null);
8680
- insert(_el$20, createComponent(Button, {
8949
+ insert(_el$21, createComponent(Button, {
8681
8950
  variant: "ghost",
8682
8951
  onClick: onToggleShowAccountUrl,
8683
8952
  type: "button",
@@ -8695,7 +8964,7 @@ var AccountPicker = (props) => {
8695
8964
  });
8696
8965
  }
8697
8966
  }), null);
8698
- insert(_el$17, createComponent(Tooltip2, {
8967
+ insert(_el$18, createComponent(Tooltip2, {
8699
8968
  get open() {
8700
8969
  return isCopyTooltipOpen();
8701
8970
  },
@@ -8721,22 +8990,22 @@ var AccountPicker = (props) => {
8721
8990
  }), createComponent(TooltipContent2, {
8722
8991
  "class": "tooltip-content",
8723
8992
  get children() {
8724
- return _tmpl$9();
8993
+ return _tmpl$92();
8725
8994
  }
8726
8995
  })];
8727
8996
  }
8728
- }), _el$22);
8729
- insert(_el$22, createComponent(Button, {
8997
+ }), _el$23);
8998
+ insert(_el$23, createComponent(Button, {
8730
8999
  variant: "secondary",
8731
9000
  onClick: () => setShowSignOutConfirm(false),
8732
9001
  children: "Cancel"
8733
9002
  }), null);
8734
- insert(_el$22, createComponent(Button, {
9003
+ insert(_el$23, createComponent(Button, {
8735
9004
  onClick: onLogout,
8736
9005
  "class": "sign-out-confirm",
8737
9006
  children: "Sign out"
8738
9007
  }), null);
8739
- return _el$17;
9008
+ return _el$18;
8740
9009
  })()];
8741
9010
  }
8742
9011
  })];
@@ -8748,14 +9017,12 @@ var AccountPicker = (props) => {
8748
9017
  })();
8749
9018
  };
8750
9019
  var AVATAR_MAX_SIZE = 512;
8751
- async function compressAvatar(file) {
9020
+ async function compressAvatar(file, crop) {
8752
9021
  const bitmap = await createImageBitmap(file);
8753
- const scale = Math.min(1, AVATAR_MAX_SIZE / Math.max(bitmap.width, bitmap.height));
8754
- const width = Math.round(bitmap.width * scale);
8755
- const height = Math.round(bitmap.height * scale);
8756
- const canvas = new OffscreenCanvas(width, height);
9022
+ const side = Math.round(Math.min(AVATAR_MAX_SIZE, crop.size));
9023
+ const canvas = new OffscreenCanvas(side, side);
8757
9024
  const ctx = canvas.getContext("2d");
8758
- ctx.drawImage(bitmap, 0, 0, width, height);
9025
+ ctx.drawImage(bitmap, crop.x, crop.y, crop.size, crop.size, 0, 0, side, side);
8759
9026
  bitmap.close();
8760
9027
  const blob = await canvas.convertToBlob({
8761
9028
  type: "image/webp",
@@ -8775,9 +9042,9 @@ function EyeOffIcon() {
8775
9042
  }
8776
9043
  function CopyIcon(props) {
8777
9044
  return (() => {
8778
- var _el$25 = _tmpl$14();
8779
- createRenderEffect(() => setAttribute(_el$25, "class", props.class ?? "icon"));
8780
- return _el$25;
9045
+ var _el$26 = _tmpl$14();
9046
+ createRenderEffect(() => setAttribute(_el$26, "class", props.class ?? "icon"));
9047
+ return _el$26;
8781
9048
  })();
8782
9049
  }
8783
9050
  var AccountPickerTool = (handle, element) => {
@@ -8799,4 +9066,4 @@ export {
8799
9066
  AccountPicker,
8800
9067
  AccountPickerTool
8801
9068
  };
8802
- //# sourceMappingURL=AccountPicker-HMEN6MEN.js.map
9069
+ //# sourceMappingURL=AccountPicker-HB6MDLKN.js.map