@saasquatch/mint-components 2.1.8-21 → 2.1.8-22

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 (42) hide show
  1. package/dist/cjs/sqm-share-link.cjs.entry.js +271 -0
  2. package/dist/cjs/sqm-stencilbook.cjs.entry.js +1144 -588
  3. package/dist/cjs/useShareLink-1282123e.js +422 -0
  4. package/dist/cjs/useShareLink-3c22b1b9.js +448 -0
  5. package/dist/cjs/useShareLink-54e24928.js +448 -0
  6. package/dist/cjs/useShareLink-b664fbc7.js +450 -0
  7. package/dist/cjs/useShareLink-bf04b25c.js +450 -0
  8. package/dist/cjs/useShareLink-e8e2ae6d.js +448 -0
  9. package/dist/collection/components/sqm-share-link/sqm-share-link-view.js +2 -28
  10. package/dist/esm/sqm-share-link.entry.js +267 -0
  11. package/dist/esm/sqm-stencilbook.entry.js +3327 -2771
  12. package/dist/esm/useShareLink-023284f3.js +445 -0
  13. package/dist/esm/useShareLink-436e9cad.js +445 -0
  14. package/dist/esm/useShareLink-4ba01373.js +447 -0
  15. package/dist/esm/useShareLink-79056582.js +445 -0
  16. package/dist/esm/useShareLink-a3329e33.js +419 -0
  17. package/dist/esm/useShareLink-bc20ec4c.js +447 -0
  18. package/dist/esm-es5/sqm-share-link.entry.js +1 -0
  19. package/dist/esm-es5/sqm-stencilbook.entry.js +1 -1
  20. package/dist/esm-es5/useShareLink-023284f3.js +1 -0
  21. package/dist/esm-es5/useShareLink-436e9cad.js +1 -0
  22. package/dist/esm-es5/useShareLink-4ba01373.js +1 -0
  23. package/dist/esm-es5/useShareLink-79056582.js +1 -0
  24. package/dist/esm-es5/useShareLink-a3329e33.js +1 -0
  25. package/dist/esm-es5/useShareLink-bc20ec4c.js +1 -0
  26. package/dist/mint-components/sqm-share-link.entry.js +267 -0
  27. package/dist/mint-components/sqm-share-link.system.entry.js +1 -0
  28. package/dist/mint-components/sqm-stencilbook.entry.js +22106 -0
  29. package/dist/mint-components/sqm-stencilbook.system.entry.js +1 -0
  30. package/dist/mint-components/useShareLink-023284f3.js +445 -0
  31. package/dist/mint-components/useShareLink-1d7c9fd8.system.js +1 -0
  32. package/dist/mint-components/useShareLink-211e061c.system.js +1 -0
  33. package/dist/mint-components/useShareLink-2de7ffce.system.js +1 -0
  34. package/dist/mint-components/useShareLink-436e9cad.js +445 -0
  35. package/dist/mint-components/useShareLink-454939f5.system.js +1 -0
  36. package/dist/mint-components/useShareLink-4ba01373.js +447 -0
  37. package/dist/mint-components/useShareLink-79056582.js +445 -0
  38. package/dist/mint-components/useShareLink-a3329e33.js +419 -0
  39. package/dist/mint-components/useShareLink-bc20ec4c.js +447 -0
  40. package/dist/mint-components/useShareLink-c05fe151.system.js +1 -0
  41. package/dist/mint-components/useShareLink-cb5abd96.system.js +1 -0
  42. package/package.json +1 -1
@@ -0,0 +1,447 @@
1
+ import { h } from './index-d9876cd5.js';
2
+ import { i as intl } from './global-e1c1ff72.js';
3
+ import { i as useState, k as useRef } from './dom-context-hooks.module-8411297a.js';
4
+ import { d as dist, H, J, B, F as Fn, w as wn, $ as $e, X as Xe, h as Qe } from './index.module-60e4da3a.js';
5
+ import { c as createStyleSheet } from './JSS-8c381d8b.js';
6
+ import { R as REFERRAL_CODES_NAMESPACE, S as SET_CODE_COPIED } from './useReferralCodes-cff9a9dc.js';
7
+ import { C as CopyTextView } from './copy-text-view-c508f2e1.js';
8
+
9
+ const vanillaStyle = `
10
+ :host {
11
+ display: block;
12
+ width: 100%;
13
+ }
14
+ `;
15
+ function ShareLinkView(props) {
16
+ const { copyTextViewProps, customizeUrl, customizeLinkLabel, saveLabelText, cancelLabelText, isEditing, editValue, domainPrefix, editsRemaining, maxEdits, limitReached, validationError, isValidating, isSaving, characterLimit, minCharacters, charactersRemaining, editLimitText, editLimitReachedText, supportLinkText, customizeDisabled, customizeDisabledTooltip, onCustomizeClick, onEditValueChange, onSave, onCancel, } = props;
17
+ const style = {
18
+ Container: {
19
+ display: "flex",
20
+ flexDirection: "column",
21
+ gap: "var(--sl-spacing-xx-small)",
22
+ width: "100%",
23
+ },
24
+ CustomizeLinkText: {
25
+ margin: "0",
26
+ fontSize: "var(--sl-font-size-small)",
27
+ fontWeight: "600",
28
+ cursor: "pointer",
29
+ color: "var(--sl-color-neutral-900)",
30
+ textAlign: "left",
31
+ padding: "var(--sl-spacing-small)",
32
+ "&:hover": {
33
+ textDecoration: "underline",
34
+ },
35
+ },
36
+ CustomizeLinkDisabled: {
37
+ margin: "0",
38
+ fontSize: "var(--sl-font-size-small)",
39
+ fontWeight: "600",
40
+ color: "var(--sl-color-neutral-400)",
41
+ cursor: "default",
42
+ textAlign: "left",
43
+ padding: "var(--sl-spacing-small)",
44
+ },
45
+ EditContainer: {
46
+ display: "flex",
47
+ flexDirection: "column",
48
+ gap: "var(--sl-spacing-x-small)",
49
+ width: "100%",
50
+ },
51
+ EditInputWrapper: {
52
+ display: "flex",
53
+ alignItems: "center",
54
+ width: "100%",
55
+ border: "var(--sqm-border-thickness, 1px) solid var(--sqm-input-border-color, #d1d5db)",
56
+ borderRadius: "var(--sqm-border-radius-normal, 4px)",
57
+ background: "var(--sqm-input-background, #fff)",
58
+ overflow: "hidden",
59
+ "&:focus-within": {
60
+ borderColor: "#999999",
61
+ boxShadow: "0 0 0 var(--sl-focus-ring-width) var(--sl-input-focus-ring-color)",
62
+ },
63
+ },
64
+ DomainPrefix: {
65
+ padding: "0 0 0 var(--sl-spacing-medium)",
66
+ fontSize: "var(--sl-font-size-medium)",
67
+ color: "var(--sl-color-neutral-500)",
68
+ whiteSpace: "nowrap",
69
+ userSelect: "none",
70
+ lineHeight: "var(--sl-input-height-medium)",
71
+ },
72
+ EditInput: {
73
+ flex: "1",
74
+ border: "none",
75
+ outline: "none",
76
+ padding: "0 var(--sl-spacing-medium) 0 0",
77
+ fontSize: "var(--sl-font-size-medium)",
78
+ fontFamily: "var(--sl-font-sans)",
79
+ color: "var(--sl-input-color)",
80
+ background: "transparent",
81
+ lineHeight: "var(--sl-input-height-medium)",
82
+ minWidth: "0",
83
+ },
84
+ EditLabel: {
85
+ margin: "0",
86
+ fontSize: "var(--sl-font-size-small)",
87
+ color: "var(--sl-color-neutral-500)",
88
+ },
89
+ HelperText: {
90
+ margin: "0",
91
+ fontSize: "var(--sl-font-size-small)",
92
+ color: "var(--sl-color-neutral-500)",
93
+ },
94
+ ErrorText: {
95
+ margin: "0",
96
+ fontSize: "var(--sl-font-size-small)",
97
+ color: "var(--sqm-danger-color-text, #dc2626)",
98
+ },
99
+ ActionRow: {
100
+ display: "flex",
101
+ gap: "var(--sl-spacing-medium)",
102
+ alignItems: "center",
103
+ },
104
+ SaveButton: {
105
+ cursor: "pointer",
106
+ fontFamily: "var(--sl-font-sans)",
107
+ fontSize: "var(--sl-font-size-small)",
108
+ fontWeight: "600",
109
+ padding: "var(--sl-spacing-x-small) var(--sl-spacing-medium)",
110
+ borderRadius: "var(--sqm-border-radius-normal, 4px)",
111
+ border: "1px solid var(--sl-color-neutral-900)",
112
+ background: "var(--sl-color-neutral-900)",
113
+ color: "#fff",
114
+ "&:disabled": {
115
+ opacity: "0.5",
116
+ cursor: "default",
117
+ },
118
+ },
119
+ CancelButton: {
120
+ margin: "0",
121
+ fontSize: "var(--sl-font-size-small)",
122
+ fontWeight: "600",
123
+ cursor: "pointer",
124
+ background: "none",
125
+ border: "none",
126
+ padding: "0",
127
+ fontFamily: "var(--sl-font-sans)",
128
+ color: "var(--sl-color-neutral-500)",
129
+ },
130
+ LimitReachedContainer: {
131
+ display: "flex",
132
+ alignItems: "center",
133
+ gap: "var(--sl-spacing-x-small)",
134
+ },
135
+ };
136
+ const sheet = createStyleSheet(style);
137
+ const styleString = sheet.toString();
138
+ const errorMessageType = (validationError === null || validationError === void 0 ? void 0 : validationError.code) === "EXISTING_CODE_CONFLICT" ? "info" : "warning";
139
+ const showCharactersRemaining = charactersRemaining <= 14;
140
+ console.log(customizeUrl, limitReached, customizeDisabled, validationError, "customize URL state");
141
+ // Editing state
142
+ if (isEditing) {
143
+ return (h("div", { class: sheet.classes.Container },
144
+ h("style", { type: "text/css" },
145
+ styleString,
146
+ vanillaStyle),
147
+ h("p", { class: sheet.classes.EditLabel }, "Enter your link"),
148
+ h("div", { class: sheet.classes.EditInputWrapper },
149
+ h("span", { class: sheet.classes.DomainPrefix }, domainPrefix),
150
+ h("input", { class: sheet.classes.EditInput, type: "text", value: editValue, onInput: (e) => onEditValueChange(e.target.value), onKeyDown: (e) => {
151
+ if (e.key === "/" || e.key === "@")
152
+ e.preventDefault();
153
+ }, disabled: isSaving, maxLength: characterLimit })),
154
+ h("p", { class: sheet.classes.HelperText },
155
+ editLimitText,
156
+ showCharactersRemaining &&
157
+ ` Characters remaining: ${charactersRemaining}`),
158
+ validationError && (h("sqm-form-message", { type: errorMessageType, style: { paddingBottom: "var(--sl-spacing-xx-small)" } },
159
+ h("p", { part: "alert-title" }, validationError.title),
160
+ validationError.description)),
161
+ isValidating && h("p", { class: sheet.classes.HelperText }, "Validating..."),
162
+ h("div", { class: sheet.classes.ActionRow },
163
+ h("sl-button", {
164
+ // class={sheet.classes.SaveButton}
165
+ type: "primary", onClick: onSave, disabled: isSaving ||
166
+ isValidating ||
167
+ !!validationError ||
168
+ !editValue ||
169
+ editValue.length < minCharacters }, isSaving ? "Saving..." : saveLabelText),
170
+ h("sl-button", { type: "secondary", class: sheet.classes.CancelButton, onClick: onCancel, disabled: isSaving }, cancelLabelText))));
171
+ }
172
+ // Default / Customized / Limit reached states
173
+ return (h("div", { class: sheet.classes.Container },
174
+ h("style", { type: "text/css" },
175
+ styleString,
176
+ vanillaStyle),
177
+ h(CopyTextView, Object.assign({}, copyTextViewProps)),
178
+ customizeUrl &&
179
+ (customizeDisabled ? (h("sl-tooltip", { content: customizeDisabledTooltip, placement: "top", style: { display: "inline-block", width: "fit-content" } },
180
+ h("p", { class: sheet.classes.CustomizeLinkDisabled }, customizeLinkLabel))) : (h("div", { class: sheet.classes.LimitReachedContainer },
181
+ h("p", { class: limitReached
182
+ ? sheet.classes.CustomizeLinkDisabled
183
+ : sheet.classes.CustomizeLinkText, onClick: limitReached ? undefined : onCustomizeClick }, customizeLinkLabel),
184
+ customizeUrl && limitReached && (h("p", { class: sheet.classes.HelperText }, intl.formatMessage({
185
+ id: "editLimitReached",
186
+ defaultMessage: editLimitReachedText,
187
+ }, {
188
+ supportLink: (h("a", { target: "_blank", href: "https://help.impact.com/other/readme/get-help-and-support" }, supportLinkText)),
189
+ }))))))));
190
+ }
191
+
192
+ const MAX_EDITS = 5;
193
+ const CHARACTER_LIMIT = 15;
194
+ const MIN_CHARACTERS = 3;
195
+ const MessageLinkQuery = dist.gql `
196
+ query ($programId: ID) {
197
+ user: viewer {
198
+ ... on User {
199
+ shareLink(programId: $programId)
200
+ }
201
+ }
202
+ }
203
+ `;
204
+ const WIDGET_ENGAGEMENT_EVENT = dist.gql `
205
+ mutation loadEvent($eventMeta: UserAnalyticsEvent!) {
206
+ createUserAnalyticsEvent(eventMeta: $eventMeta)
207
+ }
208
+ `;
209
+ const ADD_SHARE_LINK_CODE = dist.gql `
210
+ mutation ($addShareLinkCodeInput: AddShareLinkCodeInput!) {
211
+ addShareLinkCode(addShareLinkCodeInput: $addShareLinkCodeInput) {
212
+ linkCode {
213
+ linkCode
214
+ shortUrl
215
+ referralCode {
216
+ code
217
+ }
218
+ }
219
+ }
220
+ }
221
+ `;
222
+ const VALIDATE_LINK_CODE = dist.gql `
223
+ query validateLinkCode($linkCode: String!) {
224
+ validateLinkCode(linkCode: $linkCode) {
225
+ valid
226
+ invalidReason
227
+ }
228
+ }
229
+ `;
230
+ const GET_LINK_DOMAIN = dist.gql `
231
+ query getLinkDomain {
232
+ tenantSettings {
233
+ primaryLinkDomain {
234
+ host
235
+ }
236
+ }
237
+ }
238
+ `;
239
+ const SHARE_LINK_EDIT_COUNT = dist.gql `
240
+ query shareLinkEditCount {
241
+ viewer {
242
+ ... on User {
243
+ shareLinkCodes {
244
+ totalCount
245
+ data {
246
+ isVanity
247
+ }
248
+ }
249
+ }
250
+ }
251
+ }
252
+ `;
253
+ function parseShareUrl(url) {
254
+ try {
255
+ const parsed = new URL(url);
256
+ return {
257
+ url: parsed.origin + parsed.pathname,
258
+ domain: parsed.origin + "/",
259
+ path: parsed.pathname.slice(1),
260
+ };
261
+ }
262
+ catch {
263
+ return { url, domain: url, path: "" };
264
+ }
265
+ }
266
+ function useShareLink(props) {
267
+ var _a, _b, _c, _d, _e, _f, _g;
268
+ const { programId = H() } = props;
269
+ const user = J();
270
+ const engagementMedium = B();
271
+ const contextData = Fn(REFERRAL_CODES_NAMESPACE);
272
+ const { data, refetch } = wn(MessageLinkQuery, { programId }, !(user === null || user === void 0 ? void 0 : user.jwt) || !!props.linkOverride || (contextData === null || contextData === void 0 ? void 0 : contextData.shareLink) !== undefined);
273
+ const [sendLoadEvent] = $e(WIDGET_ENGAGEMENT_EVENT);
274
+ const [setCopied] = $e(SET_CODE_COPIED);
275
+ const [addShareLinkCode, { loading: isSaving }] = $e(ADD_SHARE_LINK_CODE);
276
+ const [validateLinkCode] = Xe(VALIDATE_LINK_CODE);
277
+ const { refresh } = Qe();
278
+ const { data: linkDomainData } = wn(GET_LINK_DOMAIN, {}, !(user === null || user === void 0 ? void 0 : user.jwt) || !props.customizeUrl);
279
+ const { data: editCountData, refetch: refetchEditCount } = wn(SHARE_LINK_EDIT_COUNT, {}, !(user === null || user === void 0 ? void 0 : user.jwt) || !props.customizeUrl);
280
+ const { url: copyString, domain: domainPrefix, path: pathSuffix, } = parseShareUrl((_b = ((contextData === null || contextData === void 0 ? void 0 : contextData.shareLink) || ((_a = data === null || data === void 0 ? void 0 : data.user) === null || _a === void 0 ? void 0 : _a.shareLink))) !== null && _b !== void 0 ? _b :
281
+ // Shown during loading
282
+ "...");
283
+ const [open, setOpen] = useState(false);
284
+ const [isEditing, setIsEditing] = useState(false);
285
+ const [editValue, setEditValue] = useState("");
286
+ const [validationError, setValidationError] = useState(null);
287
+ const [isValidating, setIsValidating] = useState(false);
288
+ const debounceTimerRef = useRef(undefined);
289
+ const hasPrimaryLinkDomain = ((_c = linkDomainData === null || linkDomainData === void 0 ? void 0 : linkDomainData.tenantSettings) === null || _c === void 0 ? void 0 : _c.primaryLinkDomain) != null;
290
+ const customizeDisabled = !hasPrimaryLinkDomain;
291
+ const vanityCount = (_g = (_f = (_e = (_d = editCountData === null || editCountData === void 0 ? void 0 : editCountData.viewer) === null || _d === void 0 ? void 0 : _d.shareLinkCodes) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.filter((code) => code.isVanity).length) !== null && _g !== void 0 ? _g : 0;
292
+ const editCount = vanityCount;
293
+ const editsRemaining = Math.max(0, MAX_EDITS - editCount);
294
+ const limitReached = editsRemaining <= 0;
295
+ function mapErrorCodeToInfo(errorCode) {
296
+ if (!errorCode)
297
+ return null;
298
+ const errorMap = {
299
+ EXISTING_CODE_CONFLICT: {
300
+ code: "EXISTING_CODE_CONFLICT",
301
+ title: props.existingCodeConflictErrorTitle,
302
+ description: props.existingCodeConflictErrorDescription,
303
+ },
304
+ INVALID_CHARACTER: {
305
+ code: "INVALID_CHARACTER",
306
+ title: props.invalidCharactersErrorTitle,
307
+ description: props.invalidCharactersErrorDescription,
308
+ },
309
+ BLOCKED_WORD: {
310
+ code: "BLOCKED_WORD",
311
+ title: props.profanityErrorTitle,
312
+ description: props.profanityErrorDescription,
313
+ },
314
+ };
315
+ return errorMap[errorCode];
316
+ }
317
+ async function onClick() {
318
+ if (contextData) {
319
+ await setCopied({ referralCode: contextData.referralCode });
320
+ contextData.refresh();
321
+ }
322
+ // Should well supported: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard#browser_compatibility
323
+ // Only if called from a user-initiated event
324
+ navigator.clipboard.writeText(copyString);
325
+ setOpen(true);
326
+ setTimeout(() => setOpen(false), props.tooltiplifespan);
327
+ sendLoadEvent({
328
+ eventMeta: {
329
+ programId,
330
+ id: user === null || user === void 0 ? void 0 : user.id,
331
+ accountId: user === null || user === void 0 ? void 0 : user.accountId,
332
+ type: "USER_REFERRAL_PROGRAM_ENGAGEMENT_EVENT",
333
+ meta: {
334
+ engagementMedium,
335
+ shareMedium: "DIRECT",
336
+ },
337
+ },
338
+ });
339
+ }
340
+ function onCustomizeClick() {
341
+ if (limitReached || customizeDisabled)
342
+ return;
343
+ setIsEditing(true);
344
+ setEditValue(editCount === 0 ? "" : pathSuffix);
345
+ setValidationError(null);
346
+ }
347
+ function onEditValueChange(value) {
348
+ const trimmed = value.slice(0, CHARACTER_LIMIT);
349
+ setEditValue(trimmed);
350
+ setValidationError(null);
351
+ if (debounceTimerRef.current)
352
+ clearTimeout(debounceTimerRef.current);
353
+ if (!trimmed || trimmed.length < MIN_CHARACTERS) {
354
+ setIsValidating(false);
355
+ return;
356
+ }
357
+ setIsValidating(true);
358
+ debounceTimerRef.current = setTimeout(async () => {
359
+ var _a, _b;
360
+ try {
361
+ const result = await validateLinkCode({ linkCode: trimmed });
362
+ if (!((_a = result === null || result === void 0 ? void 0 : result.validateLinkCode) === null || _a === void 0 ? void 0 : _a.valid)) {
363
+ const reason = (_b = result === null || result === void 0 ? void 0 : result.validateLinkCode) === null || _b === void 0 ? void 0 : _b.invalidReason;
364
+ console.log(reason, "validation error reason from validateLinkCode query");
365
+ setValidationError(mapErrorCodeToInfo(reason));
366
+ }
367
+ }
368
+ catch {
369
+ // Validation query failed — don't block the user
370
+ }
371
+ setIsValidating(false);
372
+ }, 2000);
373
+ }
374
+ async function onSave() {
375
+ var _a, _b;
376
+ if (!editValue ||
377
+ editValue.length < MIN_CHARACTERS ||
378
+ validationError ||
379
+ isValidating)
380
+ return;
381
+ try {
382
+ await addShareLinkCode({
383
+ addShareLinkCodeInput: {
384
+ userId: user === null || user === void 0 ? void 0 : user.id,
385
+ accountId: user === null || user === void 0 ? void 0 : user.accountId,
386
+ programId,
387
+ linkCode: editValue,
388
+ makeShareLinkCodePrimaryForReferralCode: true,
389
+ },
390
+ });
391
+ setIsEditing(false);
392
+ await Promise.all([refetch(), refetchEditCount()]);
393
+ refresh();
394
+ }
395
+ catch (e) {
396
+ const errorCode = (_a = e === null || e === void 0 ? void 0 : e.extensions) === null || _a === void 0 ? void 0 : _a.code;
397
+ console.log(errorCode, "errorCode from addSharelInkCodeMutation");
398
+ setValidationError((_b = mapErrorCodeToInfo(errorCode)) !== null && _b !== void 0 ? _b : {
399
+ code: null,
400
+ title: "Error",
401
+ description: (e === null || e === void 0 ? void 0 : e.message) || "Failed to save custom link. Please try again.",
402
+ });
403
+ }
404
+ }
405
+ function onCancel() {
406
+ setIsEditing(false);
407
+ setEditValue("");
408
+ setValidationError(null);
409
+ setIsValidating(false);
410
+ }
411
+ console.log(validationError, "validation error state"); // TEMP --- IGNORE ---
412
+ return {
413
+ copyTextViewProps: {
414
+ ...props,
415
+ onClick,
416
+ open,
417
+ copyString,
418
+ },
419
+ customizeUrl: props.customizeUrl,
420
+ customizeLinkLabel: props.customizeLinkLabel,
421
+ saveLabelText: props.saveLabelText,
422
+ cancelLabelText: props.cancelLabelText,
423
+ isEditing,
424
+ editValue,
425
+ domainPrefix,
426
+ editsRemaining,
427
+ maxEdits: MAX_EDITS,
428
+ limitReached,
429
+ validationError,
430
+ isValidating,
431
+ isSaving,
432
+ characterLimit: CHARACTER_LIMIT,
433
+ minCharacters: MIN_CHARACTERS,
434
+ charactersRemaining: CHARACTER_LIMIT - editValue.length,
435
+ editLimitText: props.editLimitText,
436
+ editLimitReachedText: props.editLimitReachedText,
437
+ supportLinkText: props.supportLinkText,
438
+ customizeDisabled,
439
+ customizeDisabledTooltip: props.customizeDisabledTooltip,
440
+ onCustomizeClick,
441
+ onEditValueChange,
442
+ onSave,
443
+ onCancel,
444
+ };
445
+ }
446
+
447
+ export { ShareLinkView as S, useShareLink as u };