issue-sticker 0.6.0 → 0.8.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.
@@ -1,83 +1,8 @@
1
- import { d as OVERLAY_LAYER_INDEX, q as gzip_1, r as record, a as cn, o as useCallbackRef$1, h as useComposedRefs, e as Primitive, P as Presence, i as Portal$1, f as composeEventHandlers, j as createContextScope, k as createSlot, D as DismissableLayer, C as Content, t as createPopperScope, l as useControllableState, v as Root2$1, m as useId, A as Anchor, w as Arrow, b as usePortalContainer, O as OVERLAY_LAYER, s as stopEscapePropagation, n as useLayoutEffect2, V as VISUALLY_HIDDEN_STYLES, c as createLucideIcon, x as clsx, S as Slot$2 } from "./createLucideIcon-BzRMP02h.js";
1
+ import { q as gzip_1, r as record, a as cn, o as useCallbackRef$1, h as useComposedRefs, e as Primitive, P as Presence, i as Portal$1, f as composeEventHandlers, j as createContextScope, k as createSlot, D as DismissableLayer, C as Content, t as createPopperScope, l as useControllableState, v as Root2$1, m as useId, A as Anchor, w as Arrow, b as usePortalContainer, d as OVERLAY_LAYER, s as stopEscapePropagation, n as useLayoutEffect2, V as VISUALLY_HIDDEN_STYLES, c as createLucideIcon, x as clsx, S as Slot$2, O as OVERLAY_LAYER_INDEX, M as MousePointer2 } from "./mouse-pointer-2-BR00y3ir.js";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import React__default, { useState, createContext, useContext, useCallback, useRef, useLayoutEffect, useEffect, useMemo } from "react";
5
5
  import * as ReactDOM from "react-dom";
6
- const ISSUE_STICKER_HOST_ELEMENT_ID = "issue-sticker-host";
7
- const ISSUE_STICKER_RUNTIME_OWNER_ATTRIBUTE = "data-issue-sticker-runtime";
8
- const ISSUE_STICKER_EXTENSION_RUNTIME_READY_EVENT = "issue-sticker:extension-runtime-ready";
9
- const ISSUE_STICKER_RUNTIME_OWNER = {
10
- extension: "extension",
11
- sdk: "sdk"
12
- };
13
- function resolveDocument(doc) {
14
- return typeof document === "undefined" ? null : document;
15
- }
16
- function getIssueStickerRuntimeHost(doc) {
17
- var _a;
18
- return ((_a = resolveDocument()) == null ? void 0 : _a.getElementById(ISSUE_STICKER_HOST_ELEMENT_ID)) ?? null;
19
- }
20
- function getIssueStickerRuntimeOwner(element) {
21
- const owner = element == null ? void 0 : element.getAttribute(ISSUE_STICKER_RUNTIME_OWNER_ATTRIBUTE);
22
- if (owner === ISSUE_STICKER_RUNTIME_OWNER.extension || owner === ISSUE_STICKER_RUNTIME_OWNER.sdk) {
23
- return owner;
24
- }
25
- return null;
26
- }
27
- function markIssueStickerRuntimeHost(element, owner) {
28
- element.setAttribute(ISSUE_STICKER_RUNTIME_OWNER_ATTRIBUTE, owner);
29
- }
30
- function createRuntimeHostElement(owner, doc) {
31
- const targetDocument = resolveDocument();
32
- if (!targetDocument) {
33
- throw new Error("createRuntimeHostElement: document 를 찾을 수 없습니다.");
34
- }
35
- const hostElement = targetDocument.createElement("div");
36
- hostElement.id = ISSUE_STICKER_HOST_ELEMENT_ID;
37
- markIssueStickerRuntimeHost(hostElement, owner);
38
- hostElement.style.all = "initial";
39
- hostElement.style.position = "fixed";
40
- hostElement.style.top = "0";
41
- hostElement.style.left = "0";
42
- hostElement.style.width = "0";
43
- hostElement.style.height = "0";
44
- hostElement.style.overflow = "visible";
45
- hostElement.style.background = "transparent";
46
- hostElement.style.pointerEvents = "none";
47
- hostElement.style.zIndex = String(OVERLAY_LAYER_INDEX.runtimeHost);
48
- hostElement.style.display = "block";
49
- hostElement.style.isolation = "isolate";
50
- return hostElement;
51
- }
52
- function isEditableTarget(target) {
53
- if (!(target instanceof HTMLElement)) return false;
54
- return target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable === true;
55
- }
56
- function attachHostTypingGuard(shadowRoot) {
57
- const handleKeyDown = (event) => {
58
- const keyboardEvent = event;
59
- if (keyboardEvent.ctrlKey || keyboardEvent.metaKey || keyboardEvent.altKey) return;
60
- if (keyboardEvent.key === "Escape") return;
61
- if (!isEditableTarget(keyboardEvent.composedPath()[0])) return;
62
- keyboardEvent.stopPropagation();
63
- };
64
- shadowRoot.addEventListener("keydown", handleKeyDown);
65
- return () => shadowRoot.removeEventListener("keydown", handleKeyDown);
66
- }
67
- const RUNTIME_OWNER_MARKER_KEY = "__issueStickerRuntimeOwner";
68
- function markerHost() {
69
- return typeof window === "undefined" ? null : window;
70
- }
71
- function getClaimedIssueStickerRuntimeOwner() {
72
- var _a;
73
- return ((_a = markerHost()) == null ? void 0 : _a[RUNTIME_OWNER_MARKER_KEY]) ?? null;
74
- }
75
- function isIssueStickerExtensionRuntimeActive(doc) {
76
- if (getClaimedIssueStickerRuntimeOwner() === ISSUE_STICKER_RUNTIME_OWNER.extension) {
77
- return true;
78
- }
79
- return getIssueStickerRuntimeOwner(getIssueStickerRuntimeHost()) === ISSUE_STICKER_RUNTIME_OWNER.extension;
80
- }
81
6
  const DEFAULT_MAX_DURATION_MS = 12e4;
82
7
  const MIME_TYPE_CANDIDATES = ["video/webm;codecs=vp9", "video/webm"];
83
8
  function createInitialSnapshot$1() {
@@ -3949,15 +3874,59 @@ class ConsoleCollector {
3949
3874
  this.logs = [];
3950
3875
  this.originals = {};
3951
3876
  this.running = false;
3877
+ this.seenErrors = /* @__PURE__ */ new WeakSet();
3878
+ this.handleWindowError = (event) => {
3879
+ if (this.markSeen(event.error)) return;
3880
+ const detail = event.error != null ? serializeArgs([event.error]) : event.message;
3881
+ this.addErrorLog(`Uncaught ${detail}`, event.error, {
3882
+ lineNumber: event.lineno || void 0,
3883
+ columnNumber: event.colno || void 0
3884
+ });
3885
+ };
3886
+ this.handleUnhandledRejection = (event) => {
3887
+ if (this.markSeen(event.reason)) return;
3888
+ this.addErrorLog(`Unhandled promise rejection: ${serializeArgs([event.reason])}`, event.reason);
3889
+ };
3890
+ this.wrappers = {};
3952
3891
  this.onChange = (options == null ? void 0 : options.onChange) ?? null;
3953
3892
  }
3893
+ /** 처음 보는 값이면 표시하고 false. 이미 본 오류 객체면 true. */
3894
+ markSeen(value) {
3895
+ if (typeof value !== "object" || value === null) return false;
3896
+ if (this.seenErrors.has(value)) return true;
3897
+ this.seenErrors.add(value);
3898
+ return false;
3899
+ }
3900
+ addErrorLog(message2, error, position) {
3901
+ this.addLog({
3902
+ type: "error",
3903
+ message: redactSensitiveText(message2),
3904
+ timestamp: Date.now(),
3905
+ url: getCurrentPageUrl() || void 0,
3906
+ ...position,
3907
+ stackTrace: redactSensitiveText(error instanceof Error ? error.stack : void 0)
3908
+ });
3909
+ }
3954
3910
  start() {
3955
3911
  if (this.running) return;
3956
3912
  this.running = true;
3913
+ if (typeof window !== "undefined") {
3914
+ window.addEventListener("error", this.handleWindowError);
3915
+ window.addEventListener("unhandledrejection", this.handleUnhandledRejection);
3916
+ }
3957
3917
  for (const method of CONSOLE_METHODS) {
3958
- this.originals[method] = console[method];
3959
- console[method] = (...args) => {
3960
- var _a;
3918
+ const original = console[method];
3919
+ this.originals[method] = original;
3920
+ const wrapper = (...args) => {
3921
+ if (this.wrappers[method] !== wrapper) {
3922
+ original.apply(console, args);
3923
+ return;
3924
+ }
3925
+ const duplicate = args.some((arg) => arg instanceof Error && this.markSeen(arg));
3926
+ if (duplicate) {
3927
+ original.apply(console, args);
3928
+ return;
3929
+ }
3961
3930
  this.addLog({
3962
3931
  type: methodToLogType(method),
3963
3932
  message: serializeArgs(args),
@@ -3965,19 +3934,26 @@ class ConsoleCollector {
3965
3934
  url: getCurrentPageUrl() || void 0,
3966
3935
  stackTrace: redactSensitiveText(captureConsoleStackTrace(args))
3967
3936
  });
3968
- (_a = this.originals[method]) == null ? void 0 : _a.apply(console, args);
3937
+ original.apply(console, args);
3969
3938
  };
3939
+ this.wrappers[method] = wrapper;
3940
+ console[method] = wrapper;
3970
3941
  }
3971
3942
  }
3972
3943
  stop() {
3973
3944
  if (!this.running) return;
3974
3945
  this.running = false;
3946
+ if (typeof window !== "undefined") {
3947
+ window.removeEventListener("error", this.handleWindowError);
3948
+ window.removeEventListener("unhandledrejection", this.handleUnhandledRejection);
3949
+ }
3975
3950
  for (const method of CONSOLE_METHODS) {
3976
- if (this.originals[method]) {
3951
+ if (this.originals[method] && console[method] === this.wrappers[method]) {
3977
3952
  console[method] = this.originals[method];
3978
3953
  }
3979
3954
  }
3980
3955
  this.originals = {};
3956
+ this.wrappers = {};
3981
3957
  }
3982
3958
  /** 리로드 이전 로그를 버퍼 앞에 되돌린다. */
3983
3959
  restore(logs) {
@@ -3999,6 +3975,7 @@ class ConsoleCollector {
3999
3975
  }
4000
3976
  clear() {
4001
3977
  this.logs = [];
3978
+ this.seenErrors = /* @__PURE__ */ new WeakSet();
4002
3979
  }
4003
3980
  addLog(log) {
4004
3981
  var _a;
@@ -4990,6 +4967,182 @@ function buildJiraCreateFields(exposedFields, fieldDefinitions = [], values = {}
4990
4967
  includeReadonly: false
4991
4968
  }).filter((field) => knownFieldIds.has(normalizeJiraFieldId(field.id))).filter((field) => !CREATE_UNSUPPORTED_FIELD_IDS.has(normalizeJiraFieldId(field.id)));
4992
4969
  }
4970
+ const JIRA_FILTERABLE_FIELD_IDS = /* @__PURE__ */ new Set([
4971
+ "status",
4972
+ "priority",
4973
+ "assignee",
4974
+ "reporter",
4975
+ "fixVersions",
4976
+ "issuetype",
4977
+ "project_key",
4978
+ "sprint_id",
4979
+ "sprint_name",
4980
+ "epic_link",
4981
+ "story_points"
4982
+ ]);
4983
+ const NOTION_FILTERABLE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "multi_select", "status", "checkbox"]);
4984
+ function getJiraConfig(integration) {
4985
+ if (integration.service_type !== "JIRA") return null;
4986
+ return integration.config ?? null;
4987
+ }
4988
+ function getNotionConfig(integration) {
4989
+ if (integration.service_type !== "NOTION") return null;
4990
+ return integration.config ?? null;
4991
+ }
4992
+ function getExposedFields(config) {
4993
+ if (!(config == null ? void 0 : config.exposed_fields)) return [];
4994
+ return normalizeExposedJiraFields(
4995
+ Array.isArray(config.exposed_fields) ? config.exposed_fields : void 0
4996
+ );
4997
+ }
4998
+ function getLastKnownJiraFields(config) {
4999
+ const fields = config == null ? void 0 : config.last_known_fields;
5000
+ if (!Array.isArray(fields)) return [];
5001
+ return fields.filter(
5002
+ (field) => Boolean(field) && typeof field === "object" && typeof field.id === "string" && typeof field.name === "string"
5003
+ );
5004
+ }
5005
+ function getSelectedNotionFields(config) {
5006
+ const fields = config == null ? void 0 : config.selected_fields;
5007
+ if (!Array.isArray(fields)) return [];
5008
+ return fields.filter((field) => typeof field === "string");
5009
+ }
5010
+ function getLastKnownNotionFields(config) {
5011
+ const fields = config == null ? void 0 : config.last_known_fields;
5012
+ if (!Array.isArray(fields)) return [];
5013
+ return fields.filter(
5014
+ (field) => Boolean(field) && typeof field === "object" && typeof field.id === "string" && typeof field.name === "string" && typeof field.type === "string"
5015
+ );
5016
+ }
5017
+ const OPTION_CUSTOM_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "multi_select"]);
5018
+ function getSelectableCustomFieldOptions(field) {
5019
+ var _a;
5020
+ if (!OPTION_CUSTOM_FIELD_TYPES.has(field.field_type)) return [];
5021
+ const rawOptions = (_a = field.field_config) == null ? void 0 : _a.options;
5022
+ if (!Array.isArray(rawOptions)) return [];
5023
+ return rawOptions.filter((option) => typeof option === "string" && option.trim().length > 0).map((option) => ({ label: option, value: option }));
5024
+ }
5025
+ function getJiraOptionValue(option) {
5026
+ return option.id;
5027
+ }
5028
+ function getJiraFieldFilterOptions(field) {
5029
+ const options = field.options ?? [];
5030
+ if (!options.length) return [];
5031
+ return options.map((option) => ({
5032
+ label: option.name || option.value || option.id,
5033
+ value: getJiraOptionValue(option)
5034
+ })).filter((option) => option.value.length > 0);
5035
+ }
5036
+ function getNotionFieldFilterOptions(field) {
5037
+ if (field.type === "checkbox") {
5038
+ return [
5039
+ { label: "체크됨", value: "true" },
5040
+ { label: "체크 안 됨", value: "false" }
5041
+ ];
5042
+ }
5043
+ const options = field.options ?? [];
5044
+ if (!options.length) return [];
5045
+ return options.map((option) => ({
5046
+ label: option.name,
5047
+ value: option.name
5048
+ })).filter((option) => option.value.length > 0);
5049
+ }
5050
+ function mergeOptions(current, next) {
5051
+ const byValue = new Map(current.map((option) => [option.value, option]));
5052
+ for (const option of next) {
5053
+ if (!byValue.has(option.value)) {
5054
+ byValue.set(option.value, option);
5055
+ }
5056
+ }
5057
+ return Array.from(byValue.values()).sort((a2, b) => a2.label.localeCompare(b.label));
5058
+ }
5059
+ function upsertFilterGroup(groups, group) {
5060
+ const existing = groups.get(group.id);
5061
+ if (!existing) {
5062
+ groups.set(group.id, {
5063
+ ...group,
5064
+ options: mergeOptions([], group.options)
5065
+ });
5066
+ return;
5067
+ }
5068
+ groups.set(group.id, {
5069
+ ...existing,
5070
+ options: mergeOptions(existing.options, group.options)
5071
+ });
5072
+ }
5073
+ function appendCustomFieldFilterGroups(groups, customFields) {
5074
+ for (const field of customFields) {
5075
+ const options = getSelectableCustomFieldOptions(field);
5076
+ if (!options.length) continue;
5077
+ upsertFilterGroup(groups, {
5078
+ kind: "custom",
5079
+ id: `custom:${field.id}`,
5080
+ fieldDefinitionId: field.id,
5081
+ label: field.field_name,
5082
+ options
5083
+ });
5084
+ }
5085
+ }
5086
+ function appendJiraFieldFilterGroups(groups, exposedFieldIds, fields) {
5087
+ for (const field of fields) {
5088
+ const normalizedFieldId = normalizeJiraFieldId(field.id);
5089
+ if (!exposedFieldIds.has(normalizedFieldId) || !JIRA_FILTERABLE_FIELD_IDS.has(normalizedFieldId)) {
5090
+ continue;
5091
+ }
5092
+ const options = getJiraFieldFilterOptions(field);
5093
+ if (!options.length) continue;
5094
+ upsertFilterGroup(groups, {
5095
+ kind: "jira",
5096
+ id: `jira:${normalizedFieldId}`,
5097
+ fieldName: normalizedFieldId,
5098
+ label: field.name,
5099
+ options
5100
+ });
5101
+ }
5102
+ }
5103
+ function appendNotionFieldFilterGroups(groups, selectedFields, fields) {
5104
+ for (const field of fields) {
5105
+ if (!selectedFields.has(field.id) && !selectedFields.has(field.name)) continue;
5106
+ if (!NOTION_FILTERABLE_FIELD_TYPES.has(field.type)) continue;
5107
+ const options = getNotionFieldFilterOptions(field);
5108
+ if (!options.length) continue;
5109
+ upsertFilterGroup(groups, {
5110
+ kind: "notion",
5111
+ id: `notion:${field.id}`,
5112
+ fieldName: field.name,
5113
+ label: field.name,
5114
+ options
5115
+ });
5116
+ }
5117
+ }
5118
+ function composeIssueFilterGroups(integrations, customFields) {
5119
+ const groups = /* @__PURE__ */ new Map();
5120
+ const jiraIntegration = integrations.find((integration) => {
5121
+ const config = getJiraConfig(integration);
5122
+ return integration.is_active !== false && config;
5123
+ });
5124
+ appendCustomFieldFilterGroups(groups, customFields);
5125
+ const jiraConfig = jiraIntegration ? getJiraConfig(jiraIntegration) : null;
5126
+ const configExposedFields = getExposedFields(jiraConfig);
5127
+ if (configExposedFields.length) {
5128
+ appendJiraFieldFilterGroups(
5129
+ groups,
5130
+ new Set(configExposedFields),
5131
+ getLastKnownJiraFields(jiraConfig)
5132
+ );
5133
+ }
5134
+ for (const integration of integrations) {
5135
+ if (integration.is_active === false) continue;
5136
+ const notionConfig = getNotionConfig(integration);
5137
+ if (!notionConfig) continue;
5138
+ appendNotionFieldFilterGroups(
5139
+ groups,
5140
+ new Set(getSelectedNotionFields(notionConfig)),
5141
+ getLastKnownNotionFields(notionConfig)
5142
+ );
5143
+ }
5144
+ return Array.from(groups.values()).sort((a2, b) => a2.label.localeCompare(b.label));
5145
+ }
4993
5146
  const STABLE_ATTR_KEYS = [
4994
5147
  "data-testid",
4995
5148
  "data-test",
@@ -6509,7 +6662,7 @@ var Popover$1 = (props) => {
6509
6662
  };
6510
6663
  Popover$1.displayName = POPOVER_NAME;
6511
6664
  var ANCHOR_NAME = "PopoverAnchor";
6512
- var PopoverAnchor = React.forwardRef(
6665
+ var PopoverAnchor$1 = React.forwardRef(
6513
6666
  (props, forwardedRef) => {
6514
6667
  const { __scopePopover, ...anchorProps } = props;
6515
6668
  const context = usePopoverContext(ANCHOR_NAME, __scopePopover);
@@ -6522,7 +6675,7 @@ var PopoverAnchor = React.forwardRef(
6522
6675
  return /* @__PURE__ */ jsx(Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });
6523
6676
  }
6524
6677
  );
6525
- PopoverAnchor.displayName = ANCHOR_NAME;
6678
+ PopoverAnchor$1.displayName = ANCHOR_NAME;
6526
6679
  var TRIGGER_NAME$1 = "PopoverTrigger";
6527
6680
  var PopoverTrigger$1 = React.forwardRef(
6528
6681
  (props, forwardedRef) => {
@@ -6745,11 +6898,13 @@ function getState(open) {
6745
6898
  return open ? "open" : "closed";
6746
6899
  }
6747
6900
  var Root2 = Popover$1;
6901
+ var Anchor2 = PopoverAnchor$1;
6748
6902
  var Trigger = PopoverTrigger$1;
6749
6903
  var Portal = PopoverPortal;
6750
6904
  var Content2 = PopoverContent$1;
6751
6905
  const Popover = Root2;
6752
6906
  const PopoverTrigger = Trigger;
6907
+ const PopoverAnchor = Anchor2;
6753
6908
  const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 6, onEscapeKeyDown, ...props }, ref) => {
6754
6909
  const portalContainer = usePortalContainer();
6755
6910
  return /* @__PURE__ */ jsx(Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
@@ -12809,12 +12964,6 @@ const DEFAULT_LABELS = {
12809
12964
  badge: "가이드",
12810
12965
  close: "가이드 닫기",
12811
12966
  skip: "건너뛰기",
12812
- skipConfirmTitle: "가이드를 건너뛸까요?",
12813
- // 표면마다 진입점이 다르다(admin=헤더 아이콘, extension=더보기 메뉴, sdk=FAB 메뉴).
12814
- // 위치를 특정하면 어느 한쪽에서는 틀린 안내가 되므로 라벨만 가리킨다.
12815
- skipConfirmBody: "'가이드 다시 보기'를 클릭하면 언제든 다시 열 수 있습니다.",
12816
- skipConfirmCancel: "계속 보기",
12817
- skipConfirmConfirm: "건너뛰기",
12818
12967
  previous: "이전",
12819
12968
  next: "다음",
12820
12969
  done: "완료",
@@ -12822,8 +12971,9 @@ const DEFAULT_LABELS = {
12822
12971
  };
12823
12972
  const MASK_PADDING = 6;
12824
12973
  const CUTOUT_RADIUS = 12;
12825
- const POPOVER_WIDTH = 336;
12974
+ const POPOVER_WIDTH = 360;
12826
12975
  const POPOVER_FALLBACK_HEIGHT = 190;
12976
+ const DEFAULT_POPOVER_SIZE = { width: POPOVER_WIDTH, height: POPOVER_FALLBACK_HEIGHT };
12827
12977
  const POPOVER_GAP = 12;
12828
12978
  function clamp(value, min2, max2) {
12829
12979
  return Math.min(Math.max(value, min2), max2);
@@ -12889,12 +13039,14 @@ function areRectsEqual(previous, next) {
12889
13039
  if (!previous || !next) return previous === next;
12890
13040
  return Math.abs(previous.top - next.top) < 0.5 && Math.abs(previous.right - next.right) < 0.5 && Math.abs(previous.bottom - next.bottom) < 0.5 && Math.abs(previous.left - next.left) < 0.5 && Math.abs(previous.width - next.width) < 0.5 && Math.abs(previous.height - next.height) < 0.5;
12891
13041
  }
12892
- function getPopoverCoordinates(position, targetRect) {
13042
+ function getPopoverCoordinates(position, targetRect, size = {
13043
+ width: POPOVER_WIDTH,
13044
+ height: POPOVER_FALLBACK_HEIGHT
13045
+ }) {
12893
13046
  if (Array.isArray(position)) return position;
12894
13047
  const viewportWidth = window.innerWidth;
12895
13048
  const viewportHeight = window.innerHeight;
12896
- const width = POPOVER_WIDTH;
12897
- const height = POPOVER_FALLBACK_HEIGHT;
13049
+ const { width, height } = size;
12898
13050
  const maxX = Math.max(POPOVER_GAP, viewportWidth - width - POPOVER_GAP);
12899
13051
  const maxY = Math.max(POPOVER_GAP, viewportHeight - height - POPOVER_GAP);
12900
13052
  const xOnTarget = targetRect.left + targetRect.width / 2 - width / 2;
@@ -12928,6 +13080,49 @@ function getPopoverCoordinates(position, targetRect) {
12928
13080
  ];
12929
13081
  }
12930
13082
  }
13083
+ function rectsOverlap(a2, b) {
13084
+ return a2.left < b.right && a2.right > b.left && a2.top < b.bottom && a2.bottom > b.top;
13085
+ }
13086
+ function overlapArea(a2, b) {
13087
+ const w = Math.min(a2.right, b.right) - Math.max(a2.left, b.left);
13088
+ const h = Math.min(a2.bottom, b.bottom) - Math.max(a2.top, b.top);
13089
+ return w > 0 && h > 0 ? w * h : 0;
13090
+ }
13091
+ const SIDE_ORDER = ["bottom", "top", "right", "left"];
13092
+ const OPPOSITE = {
13093
+ top: "bottom",
13094
+ bottom: "top",
13095
+ left: "right",
13096
+ right: "left"
13097
+ };
13098
+ function resolvePopoverPlacement(position, targetRect, size, avoidRects = []) {
13099
+ if (Array.isArray(position)) return { left: position[0], top: position[1], side: null };
13100
+ if (position === "center") {
13101
+ const [left, top] = getPopoverCoordinates(position, targetRect, size);
13102
+ return { left, top, side: null };
13103
+ }
13104
+ const blockers = [targetRect, ...avoidRects];
13105
+ const requested = position ?? "bottom";
13106
+ const candidates = [requested, OPPOSITE[requested], ...SIDE_ORDER];
13107
+ let best = null;
13108
+ for (const candidate of candidates) {
13109
+ const [left, top] = getPopoverCoordinates(candidate, targetRect, size);
13110
+ const rect = {
13111
+ left,
13112
+ top,
13113
+ right: left + size.width,
13114
+ bottom: top + size.height,
13115
+ width: size.width,
13116
+ height: size.height
13117
+ };
13118
+ const area = blockers.reduce((sum, blocker) => sum + overlapArea(rect, blocker), 0);
13119
+ const placement = { left, top, side: candidate };
13120
+ if (!blockers.some((blocker) => rectsOverlap(rect, blocker))) return placement;
13121
+ if (!best || area < best.area) best = { placement, area };
13122
+ }
13123
+ const fallback = getPopoverCoordinates(requested, targetRect, size);
13124
+ return (best == null ? void 0 : best.placement) ?? { left: fallback[0], top: fallback[1], side: requested };
13125
+ }
12931
13126
  function getViewportRect() {
12932
13127
  return {
12933
13128
  top: 0,
@@ -12938,6 +13133,9 @@ function getViewportRect() {
12938
13133
  height: window.innerHeight
12939
13134
  };
12940
13135
  }
13136
+ const TAP_INSET = 8;
13137
+ const TAP_RIPPLE_SIZE = 44;
13138
+ const LINK_BUTTON_CLASS = "inline-flex h-[30px] items-center justify-center rounded-sm text-xs font-semibold text-text-tertiary underline-offset-4 transition-colors hover:text-text-primary hover:underline focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50";
12941
13139
  function shouldRenderNextButton(step) {
12942
13140
  if (step.advanceOnTargetClick) return false;
12943
13141
  if (step.advanceOn && !step.allowManualAdvance) return false;
@@ -12955,117 +13153,139 @@ function OnboardingStyleTag() {
12955
13153
  transition: opacity ${POPOVER_FADE_MS}ms ease-out;
12956
13154
  }
12957
13155
 
13156
+ @keyframes issue-sticker-onboarding-tap {
13157
+ 0%,
13158
+ 55%,
13159
+ 100% {
13160
+ transform: translate(0, 0);
13161
+ }
13162
+ 30% {
13163
+ transform: translate(-5px, -5px);
13164
+ }
13165
+ }
13166
+
13167
+ @keyframes issue-sticker-onboarding-ripple {
13168
+ 0% {
13169
+ transform: translate(-50%, -50%) scale(0.3);
13170
+ opacity: 0.5;
13171
+ }
13172
+ 55%,
13173
+ 100% {
13174
+ transform: translate(-50%, -50%) scale(1.7);
13175
+ opacity: 0;
13176
+ }
13177
+ }
13178
+
13179
+ .issue-sticker-onboarding-tap {
13180
+ animation: issue-sticker-onboarding-tap 1.6s ease-in-out infinite;
13181
+ }
13182
+
13183
+ .issue-sticker-onboarding-tap-ripple {
13184
+ animation: issue-sticker-onboarding-ripple 1.6s ease-out infinite;
13185
+ }
13186
+
13187
+ @keyframes issue-sticker-onboarding-focus {
13188
+ from {
13189
+ transform: scale(1.05);
13190
+ opacity: 0;
13191
+ }
13192
+ to {
13193
+ transform: scale(1);
13194
+ opacity: 1;
13195
+ }
13196
+ }
13197
+
13198
+ .issue-sticker-onboarding-highlight {
13199
+ animation: issue-sticker-onboarding-focus 220ms ease-out;
13200
+ }
13201
+
12958
13202
  @media (prefers-reduced-motion: reduce) {
12959
13203
  .issue-sticker-onboarding-popover {
12960
13204
  transition-duration: 1ms !important;
12961
13205
  }
12962
13206
 
12963
- .issue-sticker-onboarding-highlight {
13207
+ .issue-sticker-onboarding-highlight,
13208
+ .issue-sticker-onboarding-tap,
13209
+ .issue-sticker-onboarding-tap-ripple {
12964
13210
  animation: none !important;
12965
13211
  }
12966
13212
  }
12967
13213
  ` });
12968
13214
  }
12969
13215
  function OnboardingPopoverContent({
13216
+ allowSkip,
12970
13217
  step,
12971
13218
  clickHint,
12972
13219
  labels,
12973
13220
  canGoPrevious,
12974
13221
  isLast,
12975
13222
  isVisible,
12976
- isSkipConfirmOpen,
12977
- onRequestSkip,
12978
- onCancelSkip,
12979
- onConfirmSkip,
13223
+ onSkip,
12980
13224
  onNext,
12981
13225
  onPrevious
12982
13226
  }) {
12983
- if (isSkipConfirmOpen) {
12984
- return /* @__PURE__ */ jsxs(
12985
- "div",
12986
- {
12987
- role: "alertdialog",
12988
- "aria-modal": "false",
12989
- "aria-labelledby": "issue-sticker-onboarding-skip-title",
12990
- "aria-describedby": "issue-sticker-onboarding-skip-desc",
12991
- children: [
12992
- /* @__PURE__ */ jsx(
12993
- "h2",
12994
- {
12995
- id: "issue-sticker-onboarding-skip-title",
12996
- className: "text-sm font-semibold leading-5 text-text-primary",
12997
- children: labels.skipConfirmTitle
12998
- }
12999
- ),
13000
- /* @__PURE__ */ jsx(
13001
- "p",
13002
- {
13003
- id: "issue-sticker-onboarding-skip-desc",
13004
- className: "mt-2 whitespace-pre-line text-sm leading-5 text-text-secondary",
13005
- children: labels.skipConfirmBody
13006
- }
13007
- ),
13008
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-end gap-2", children: [
13009
- /* @__PURE__ */ jsx(
13010
- "button",
13011
- {
13012
- type: "button",
13013
- onClick: onCancelSkip,
13014
- disabled: !isVisible,
13015
- className: "inline-flex h-[30px] items-center justify-center rounded-md border border-line-subtle px-2.5 text-xs font-semibold text-text-secondary transition-colors hover:bg-surface-2 hover:text-text-primary focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50",
13016
- children: labels.skipConfirmCancel
13017
- }
13018
- ),
13019
- /* @__PURE__ */ jsx(
13020
- "button",
13021
- {
13022
- type: "button",
13023
- onClick: onConfirmSkip,
13024
- disabled: !isVisible,
13025
- className: "inline-flex h-[30px] items-center justify-center rounded-md border border-line-subtle px-2.5 text-xs font-semibold text-text-primary transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50",
13026
- children: labels.skipConfirmConfirm
13027
- }
13028
- )
13029
- ] })
13030
- ]
13031
- }
13032
- );
13033
- }
13227
+ const hasNextButton = shouldRenderNextButton(step);
13034
13228
  return /* @__PURE__ */ jsxs("div", { children: [
13035
13229
  /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold leading-5 text-text-primary", children: step.title }),
13036
- /* @__PURE__ */ jsx("p", { className: "mt-2 whitespace-pre-line text-sm leading-5 text-text-secondary", children: step.body }),
13037
- clickHint ? /* @__PURE__ */ jsxs("p", { className: "mt-2 flex items-center gap-1.5 text-xs font-semibold leading-5 text-brand", children: [
13038
- /* @__PURE__ */ jsx(MousePointerClick, { "aria-hidden": "true", className: "h-3.5 w-3.5 shrink-0" }),
13039
- clickHint
13040
- ] }) : null,
13041
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between gap-2", children: [
13042
- /* @__PURE__ */ jsx(
13043
- "button",
13230
+ /* @__PURE__ */ jsx("p", { className: "mt-2 whitespace-pre-line text-sm leading-[1.55] text-text-secondary", children: step.body }),
13231
+ step.bodyExtra ? /* @__PURE__ */ jsx("div", { className: "mt-3", children: step.bodyExtra }) : null,
13232
+ clickHint ? (
13233
+ /* 진행 버튼이 없는 단계에서는 이 줄이 유일한 다음 행동이다. 그래서 버튼이 있던
13234
+ * 자리만큼의 무게를 준다 — 작은 글줄로 두면 사용자가 못 보고 다른 버튼을 누른다. */
13235
+ /* @__PURE__ */ jsxs(
13236
+ "p",
13044
13237
  {
13045
- type: "button",
13046
- onClick: onRequestSkip,
13047
- disabled: !isVisible,
13048
- className: "inline-flex h-[30px] items-center justify-center rounded-sm text-xs font-semibold text-text-tertiary underline-offset-4 transition-colors hover:text-text-primary hover:underline focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50",
13049
- children: labels.skip
13238
+ className: cn(
13239
+ "mt-3 flex items-center gap-1.5 font-semibold text-brand",
13240
+ hasNextButton ? "text-xs leading-5" : "rounded-md border border-brand/40 bg-brand/10 px-3 py-2 text-sm leading-5"
13241
+ ),
13242
+ children: [
13243
+ /* @__PURE__ */ jsx(MousePointerClick, { "aria-hidden": "true", className: "h-4 w-4 shrink-0" }),
13244
+ clickHint
13245
+ ]
13050
13246
  }
13051
- ),
13247
+ )
13248
+ ) : null,
13249
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between gap-2", children: [
13250
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
13251
+ allowSkip ? /* @__PURE__ */ jsx(
13252
+ "button",
13253
+ {
13254
+ type: "button",
13255
+ onClick: onSkip,
13256
+ disabled: !isVisible,
13257
+ className: LINK_BUTTON_CLASS,
13258
+ children: labels.skip
13259
+ }
13260
+ ) : null,
13261
+ canGoPrevious && !hasNextButton ? /* @__PURE__ */ jsx(
13262
+ "button",
13263
+ {
13264
+ type: "button",
13265
+ onClick: onPrevious,
13266
+ disabled: !isVisible,
13267
+ className: LINK_BUTTON_CLASS,
13268
+ children: labels.previous
13269
+ }
13270
+ ) : null
13271
+ ] }),
13052
13272
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
13053
- canGoPrevious ? /* @__PURE__ */ jsx(
13273
+ canGoPrevious && hasNextButton ? /* @__PURE__ */ jsx(
13054
13274
  "button",
13055
13275
  {
13056
13276
  type: "button",
13057
13277
  onClick: onPrevious,
13058
- disabled: !isVisible || isSkipConfirmOpen,
13278
+ disabled: !isVisible,
13059
13279
  className: "inline-flex h-[30px] items-center justify-center rounded-md border border-line-subtle px-2.5 text-xs font-semibold text-text-secondary transition-colors hover:bg-surface-2 hover:text-text-primary focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50",
13060
13280
  children: labels.previous
13061
13281
  }
13062
13282
  ) : null,
13063
- shouldRenderNextButton(step) ? /* @__PURE__ */ jsx(
13283
+ hasNextButton ? /* @__PURE__ */ jsx(
13064
13284
  "button",
13065
13285
  {
13066
13286
  type: "button",
13067
13287
  onClick: onNext,
13068
- disabled: !isVisible || isSkipConfirmOpen,
13288
+ disabled: !isVisible,
13069
13289
  className: "inline-flex h-[30px] items-center justify-center rounded-md border border-line-subtle px-2.5 text-xs font-semibold text-text-primary transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50",
13070
13290
  children: isLast ? labels.done : step.nextLabel ?? labels.next
13071
13291
  }
@@ -13078,6 +13298,9 @@ function OnboardingOverlay({
13078
13298
  step,
13079
13299
  targetRect,
13080
13300
  targetRadius,
13301
+ avoidRects,
13302
+ elevateHighlight,
13303
+ allowSkip = true,
13081
13304
  className,
13082
13305
  labels,
13083
13306
  isPopoverVisible,
@@ -13088,25 +13311,45 @@ function OnboardingOverlay({
13088
13311
  onPrevious
13089
13312
  }) {
13090
13313
  const maskId = React.useId().replace(/:/g, "");
13091
- const [isSkipConfirmOpen, setIsSkipConfirmOpen] = React.useState(false);
13314
+ const renderHighlight = (node) => elevateHighlight && typeof document !== "undefined" ? ReactDOM.createPortal(node, document.body) : node;
13092
13315
  const cutoutRect = targetRect ? padRect(targetRect, MASK_PADDING) : null;
13093
13316
  const cutoutRadius = cutoutRect ? Math.min(
13094
13317
  targetRadius === null || targetRadius === void 0 ? CUTOUT_RADIUS : targetRadius + MASK_PADDING,
13095
13318
  cutoutRect.width / 2,
13096
13319
  cutoutRect.height / 2
13097
13320
  ) : 0;
13098
- const [popoverLeft, popoverTop] = getPopoverCoordinates(
13321
+ const popoverRef = React.useRef(null);
13322
+ const [popoverSize, setPopoverSize] = React.useState(
13323
+ null
13324
+ );
13325
+ React.useLayoutEffect(() => {
13326
+ const element = popoverRef.current;
13327
+ if (!element) return void 0;
13328
+ const measure = () => {
13329
+ const rect = element.getBoundingClientRect();
13330
+ setPopoverSize(
13331
+ (current) => current && Math.abs(current.height - rect.height) < 0.5 && Math.abs(current.width - rect.width) < 0.5 ? current : { width: rect.width, height: rect.height }
13332
+ );
13333
+ };
13334
+ measure();
13335
+ if (typeof ResizeObserver === "undefined") return void 0;
13336
+ const observer = new ResizeObserver(measure);
13337
+ observer.observe(element);
13338
+ return () => observer.disconnect();
13339
+ }, [step.id, step.body]);
13340
+ const effectiveSize = popoverSize && popoverSize.width > 0 && popoverSize.height > 0 ? popoverSize : DEFAULT_POPOVER_SIZE;
13341
+ const placement = resolvePopoverPlacement(
13099
13342
  step.position ?? (cutoutRect ? "bottom" : "center"),
13100
- cutoutRect ?? getViewportRect()
13343
+ cutoutRect ?? getViewportRect(),
13344
+ effectiveSize,
13345
+ cutoutRect ? avoidRects ?? [] : []
13101
13346
  );
13347
+ const { left: popoverLeft, top: popoverTop } = placement;
13102
13348
  const shouldCenterPopover = !cutoutRect && (step.position ?? "center") === "center";
13103
- const maskColor = "rgba(8, 13, 18, 0.62)";
13349
+ const maskColor = isTargetInteractionStep(step) ? "rgba(8, 13, 18, 0.74)" : "rgba(8, 13, 18, 0.62)";
13104
13350
  const isPassthrough = !!step.advanceOn;
13105
13351
  const isTargetInteraction = isTargetInteractionStep(step);
13106
13352
  const clickHint = isTargetInteraction ? step.clickHint ?? labels.clickHint : null;
13107
- React.useEffect(() => {
13108
- setIsSkipConfirmOpen(false);
13109
- }, [step.id]);
13110
13353
  return /* @__PURE__ */ jsxs(
13111
13354
  "div",
13112
13355
  {
@@ -13191,58 +13434,97 @@ function OnboardingOverlay({
13191
13434
  }
13192
13435
  }
13193
13436
  ) : null,
13194
- cutoutRect ? /* @__PURE__ */ jsx(
13195
- "div",
13196
- {
13197
- "aria-hidden": "true",
13198
- "data-testid": "onboarding-cutout-outline",
13199
- className: cn(
13200
- "fixed",
13201
- isTargetInteraction ? "issue-sticker-onboarding-highlight animate-pulse-ring border-2 border-brand" : "border border-white/90"
13202
- ),
13203
- style: {
13204
- left: cutoutRect.left,
13205
- top: cutoutRect.top,
13206
- width: cutoutRect.width,
13207
- height: cutoutRect.height,
13208
- borderRadius: cutoutRadius,
13209
- pointerEvents: "none"
13437
+ cutoutRect ? renderHighlight(
13438
+ /* @__PURE__ */ jsx(
13439
+ "div",
13440
+ {
13441
+ "aria-hidden": "true",
13442
+ "data-testid": "onboarding-cutout-outline",
13443
+ className: cn(
13444
+ "issue-sticker-onboarding-highlight fixed",
13445
+ isTargetInteraction ? "border-2 border-brand" : "border border-white/90"
13446
+ ),
13447
+ style: {
13448
+ left: cutoutRect.left,
13449
+ top: cutoutRect.top,
13450
+ width: cutoutRect.width,
13451
+ height: cutoutRect.height,
13452
+ borderRadius: cutoutRadius,
13453
+ pointerEvents: "none",
13454
+ zIndex: elevateHighlight ? OVERLAY_LAYER_INDEX.runtimeHost : void 0
13455
+ }
13456
+ },
13457
+ step.id
13458
+ )
13459
+ ) : null,
13460
+ cutoutRect && isTargetInteraction ? renderHighlight(
13461
+ /* 클릭하는 커서. 테두리만으로는 "봐야 할 곳"까지만 전달되고 "클릭하라"가
13462
+ * 전달되지 않는다. 손 모양 반복 동작이 그 자리를 맡는다. */
13463
+ /* @__PURE__ */ jsxs(
13464
+ "div",
13465
+ {
13466
+ "aria-hidden": "true",
13467
+ "data-testid": "onboarding-cutout-cursor",
13468
+ className: "issue-sticker-onboarding-tap fixed",
13469
+ style: {
13470
+ left: cutoutRect.right - TAP_INSET,
13471
+ top: cutoutRect.bottom - TAP_INSET,
13472
+ pointerEvents: "none",
13473
+ zIndex: elevateHighlight ? OVERLAY_LAYER_INDEX.runtimeHost : void 0
13474
+ },
13475
+ children: [
13476
+ /* @__PURE__ */ jsx(
13477
+ "span",
13478
+ {
13479
+ className: "issue-sticker-onboarding-tap-ripple absolute rounded-full bg-brand",
13480
+ style: { left: 0, top: 0, width: TAP_RIPPLE_SIZE, height: TAP_RIPPLE_SIZE }
13481
+ }
13482
+ ),
13483
+ /* @__PURE__ */ jsx(
13484
+ MousePointer2,
13485
+ {
13486
+ className: "relative h-8 w-8",
13487
+ style: { fill: "#ffffff", stroke: "rgba(12, 18, 15, 0.7)" },
13488
+ strokeWidth: 1.4
13489
+ }
13490
+ )
13491
+ ]
13210
13492
  }
13211
- }
13493
+ )
13212
13494
  ) : null,
13213
- isSkipConfirmOpen ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "fixed inset-0 pointer-events-auto" }) : null,
13214
- /* @__PURE__ */ jsx(
13215
- "div",
13216
- {
13217
- role: "dialog",
13218
- "aria-modal": "false",
13219
- ...{ [ONBOARDING_POPOVER_DATA_ATTR]: "floating" },
13220
- className: "issue-sticker-onboarding-popover fixed w-[21rem] max-w-[calc(100vw-24px)] rounded-xl border border-line-subtle bg-surface-0 p-[18px] text-text-primary shadow-lg pointer-events-auto",
13221
- style: {
13222
- left: shouldCenterPopover ? "50%" : popoverLeft,
13223
- top: shouldCenterPopover ? "50%" : popoverTop,
13224
- opacity: isPopoverVisible ? 1 : 0,
13225
- transform: shouldCenterPopover ? "translate(-50%, -50%)" : void 0,
13226
- zIndex: OVERLAY_LAYER_INDEX.tourPopover
13227
- },
13228
- children: /* @__PURE__ */ jsx(
13229
- OnboardingPopoverContent,
13230
- {
13231
- step,
13232
- clickHint,
13233
- labels,
13234
- canGoPrevious,
13235
- isLast,
13236
- isVisible: isPopoverVisible,
13237
- isSkipConfirmOpen,
13238
- onRequestSkip: () => setIsSkipConfirmOpen(true),
13239
- onCancelSkip: () => setIsSkipConfirmOpen(false),
13240
- onConfirmSkip: onSkip,
13241
- onNext,
13242
- onPrevious
13243
- }
13244
- )
13245
- }
13495
+ renderHighlight(
13496
+ /* @__PURE__ */ jsx(
13497
+ "div",
13498
+ {
13499
+ ref: popoverRef,
13500
+ role: "dialog",
13501
+ "aria-modal": "false",
13502
+ ...{ [ONBOARDING_POPOVER_DATA_ATTR]: "floating" },
13503
+ className: "issue-sticker-onboarding-popover fixed w-[22.5rem] max-w-[calc(100vw-24px)] break-keep [overflow-wrap:anywhere] rounded-xl border border-line-subtle bg-surface-0 p-[18px] text-text-primary shadow-lg pointer-events-auto",
13504
+ style: {
13505
+ left: shouldCenterPopover ? "50%" : popoverLeft,
13506
+ top: shouldCenterPopover ? "50%" : popoverTop,
13507
+ opacity: isPopoverVisible ? 1 : 0,
13508
+ transform: shouldCenterPopover ? "translate(-50%, -50%)" : void 0,
13509
+ zIndex: elevateHighlight ? OVERLAY_LAYER_INDEX.runtimeHost : OVERLAY_LAYER_INDEX.tourPopover
13510
+ },
13511
+ children: /* @__PURE__ */ jsx(
13512
+ OnboardingPopoverContent,
13513
+ {
13514
+ allowSkip,
13515
+ step,
13516
+ clickHint,
13517
+ labels,
13518
+ canGoPrevious,
13519
+ isLast,
13520
+ isVisible: isPopoverVisible,
13521
+ onSkip,
13522
+ onNext,
13523
+ onPrevious
13524
+ }
13525
+ )
13526
+ }
13527
+ )
13246
13528
  )
13247
13529
  ]
13248
13530
  }
@@ -13335,7 +13617,9 @@ function OnboardingProvider({
13335
13617
  className,
13336
13618
  labels: labelOverrides,
13337
13619
  storage: storageOverride,
13338
- suppressed = false
13620
+ suppressed = false,
13621
+ elevateHighlight = false,
13622
+ allowSkip = true
13339
13623
  }) {
13340
13624
  const labels = React.useMemo(() => ({ ...DEFAULT_LABELS, ...labelOverrides }), [labelOverrides]);
13341
13625
  const storage = React.useMemo(
@@ -13617,6 +13901,7 @@ function OnboardingProvider({
13617
13901
  const allTargetsResolved = activeTargetIds.length > 0 && resolvedTargetRects.every((rect) => rect !== null);
13618
13902
  const targetRect = isOpen && isActiveRoute && allTargetsResolved ? unionRect(resolvedTargetRects.filter((r2) => r2 !== null)) : null;
13619
13903
  const targetRadius = activeTargetIds.length === 1 ? getElementRadius(targetMapRef.current.get(activeTargetIds[0]) ?? null) : null;
13904
+ const avoidRects = ((activeStep == null ? void 0 : activeStep.avoidTargetIds) ?? []).map((id) => getElementRect(targetMapRef.current.get(id) ?? null)).filter((rect) => rect !== null);
13620
13905
  const shouldRenderOverlay = isOpen && activeStep && isActiveRoute && !suppressed && !activeStep.silent && (!stepHasTarget || targetRect);
13621
13906
  const isTargetReady = !stepHasTarget || targetRect !== null;
13622
13907
  React.useEffect(() => {
@@ -13668,6 +13953,9 @@ function OnboardingProvider({
13668
13953
  step: activeStep,
13669
13954
  targetRect,
13670
13955
  targetRadius,
13956
+ avoidRects,
13957
+ elevateHighlight,
13958
+ allowSkip,
13671
13959
  className,
13672
13960
  labels,
13673
13961
  isPopoverVisible,
@@ -13895,89 +14183,83 @@ function buildExternalUserPayload(user) {
13895
14183
  };
13896
14184
  }
13897
14185
  export {
13898
- X as $,
13899
- trimLogBackupPayload as A,
13900
- createSafeLogBackup as B,
14186
+ getNotionPageMetadata as $,
14187
+ getLogBackupSessionId as A,
14188
+ createIndexedDbLogBackup as B,
13901
14189
  ConsoleCollector as C,
13902
- getLogBackupSessionId as D,
13903
- createIndexedDbLogBackup as E,
13904
- PopoverTrigger as F,
13905
- Input as G,
13906
- PopoverContent as H,
14190
+ PopoverTrigger as D,
14191
+ Input as E,
14192
+ PopoverContent as F,
14193
+ Select$1 as G,
14194
+ SelectTrigger as H,
13907
14195
  ISSUE_STICKER_INTERNAL_LOG_PREFIX as I,
13908
- Select$1 as J,
13909
- SelectTrigger as K,
14196
+ SelectValue as J,
14197
+ SelectContent as K,
13910
14198
  Label as L,
13911
- SelectValue as M,
14199
+ SelectItem as M,
13912
14200
  NetworkCollector as N,
13913
- SelectContent as O,
14201
+ getJiraMetadata as O,
13914
14202
  Popover as P,
13915
- SelectItem as Q,
13916
- getJiraMetadata as R,
14203
+ buildJiraIssueFields as Q,
14204
+ Button$1 as R,
13917
14205
  ScreenRecordingController as S,
13918
- buildJiraIssueFields as T,
13919
- Button$1 as U,
13920
- Root2 as V,
13921
- Trigger as W,
13922
- ChevronDown as X,
13923
- Portal as Y,
13924
- Content2 as Z,
13925
- Check as _,
14206
+ Root2 as T,
14207
+ Trigger as U,
14208
+ ChevronDown as V,
14209
+ Portal as W,
14210
+ Content2 as X,
14211
+ Check as Y,
14212
+ X as Z,
14213
+ DatePicker as _,
13926
14214
  uploadSignedMediaWithApi as a,
13927
- DatePicker as a0,
13928
- getNotionPageMetadata as a1,
13929
- buildNotionFieldViews as a2,
13930
- DirectUploadError as a3,
13931
- toast as a4,
13932
- getSnapshot as a5,
13933
- subscribe as a6,
13934
- getRegisteredUploadId as a7,
13935
- ChevronRight as a8,
13936
- ReactRemoveScroll as a9,
13937
- hideOthers as aa,
13938
- useFocusGuards as ab,
13939
- FocusScope as ac,
13940
- getExposedJiraFields as ad,
13941
- isJiraFieldExposed as ae,
13942
- getPrimaryJiraMapping as af,
13943
- createCollection as ag,
13944
- useDirection as ah,
13945
- getPrimaryNotionMapping as ai,
13946
- buttonVariants as aj,
13947
- findElementBySelector as ak,
13948
- findElementByXPath as al,
13949
- OnboardingProvider as am,
13950
- useOnboardingTarget as an,
13951
- useOnboardingFlow as ao,
13952
- ISSUE_STICKER_HOST_ELEMENT_ID as ap,
13953
- getIssueStickerRuntimeOwner as aq,
13954
- ISSUE_STICKER_RUNTIME_OWNER as ar,
13955
- createRuntimeHostElement as as,
13956
- attachHostTypingGuard as at,
13957
- ISSUE_STICKER_EXTENSION_RUNTIME_READY_EVENT as au,
13958
- normalizeJiraFieldId as b,
14215
+ buildNotionFieldViews as a0,
14216
+ DirectUploadError as a1,
14217
+ toast as a2,
14218
+ getSnapshot as a3,
14219
+ subscribe as a4,
14220
+ getRegisteredUploadId as a5,
14221
+ ChevronRight as a6,
14222
+ ReactRemoveScroll as a7,
14223
+ hideOthers as a8,
14224
+ useFocusGuards as a9,
14225
+ FocusScope as aa,
14226
+ getExposedJiraFields as ab,
14227
+ isJiraFieldExposed as ac,
14228
+ normalizeExposedJiraFields as ad,
14229
+ getPrimaryJiraMapping as ae,
14230
+ createCollection as af,
14231
+ useDirection as ag,
14232
+ getPrimaryNotionMapping as ah,
14233
+ buttonVariants as ai,
14234
+ findElementBySelector as aj,
14235
+ findElementByXPath as ak,
14236
+ OnboardingProvider as al,
14237
+ useOnboardingTarget as am,
14238
+ useOnboardingFlow as an,
14239
+ PopoverAnchor as ao,
14240
+ buildJiraCreateFields as b,
13959
14241
  captureWithModernScreenshot as c,
13960
14242
  directUploadToSignedUrl as d,
13961
- buildJiraCreateFields as e,
13962
- buildNotionCreateFields as f,
14243
+ buildNotionCreateFields as e,
14244
+ buildGuestOwnerQuery as f,
13963
14245
  getElementPosition as g,
13964
- buildGuestOwnerQuery as h,
14246
+ composeIssueFilterGroups as h,
13965
14247
  buildIssueIntegrationsPayload as i,
13966
14248
  devLogger as j,
13967
14249
  filterExcludeServiceRelatedLogs as k,
13968
14250
  filterExcludeServiceRelatedConsoleLogs as l,
13969
14251
  compactNetworkLogsForTransport as m,
13970
- normalizeExposedJiraFields as n,
13971
- CONSOLE_LOG_SUBMIT_LIMIT as o,
14252
+ CONSOLE_LOG_SUBMIT_LIMIT as n,
14253
+ buildExternalUserPayload as o,
13972
14254
  pristineFetch as p,
13973
- buildExternalUserPayload as q,
13974
- shrinkNetworkLogsToFit as r,
14255
+ shrinkNetworkLogsToFit as q,
14256
+ measureJsonBytes as r,
13975
14257
  selectNetworkLogsForSubmit as s,
13976
- measureJsonBytes as t,
14258
+ sanitizeString as t,
13977
14259
  uploadScreenshotDataUrls as u,
13978
- sanitizeString as v,
13979
- getCurrentPageUrl as w,
13980
- SessionReplayCaptureController as x,
13981
- preloadModernScreenshot as y,
13982
- isIssueStickerExtensionRuntimeActive as z
14260
+ getCurrentPageUrl as v,
14261
+ SessionReplayCaptureController as w,
14262
+ preloadModernScreenshot as x,
14263
+ trimLogBackupPayload as y,
14264
+ createSafeLogBackup as z
13983
14265
  };