@saasquatch/mint-components 2.1.8-26 → 2.1.8-28

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