issue-sticker 0.7.0 → 0.8.1

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.
@@ -18,10 +18,12 @@ function getDefaultDisplayMedia() {
18
18
  if (typeof navigator === "undefined" || !((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia)) {
19
19
  throw new Error("Screen recording is not supported in this browser.");
20
20
  }
21
- return navigator.mediaDevices.getDisplayMedia({
22
- video: { frameRate: 30 },
23
- audio: false
24
- });
21
+ const options = {
22
+ video: { frameRate: 30, displaySurface: "browser" },
23
+ audio: false,
24
+ selfBrowserSurface: "include"
25
+ };
26
+ return navigator.mediaDevices.getDisplayMedia(options);
25
27
  }
26
28
  function createDefaultMediaRecorder(stream, options) {
27
29
  if (typeof MediaRecorder === "undefined") {
@@ -4967,6 +4969,182 @@ function buildJiraCreateFields(exposedFields, fieldDefinitions = [], values = {}
4967
4969
  includeReadonly: false
4968
4970
  }).filter((field) => knownFieldIds.has(normalizeJiraFieldId(field.id))).filter((field) => !CREATE_UNSUPPORTED_FIELD_IDS.has(normalizeJiraFieldId(field.id)));
4969
4971
  }
4972
+ const JIRA_FILTERABLE_FIELD_IDS = /* @__PURE__ */ new Set([
4973
+ "status",
4974
+ "priority",
4975
+ "assignee",
4976
+ "reporter",
4977
+ "fixVersions",
4978
+ "issuetype",
4979
+ "project_key",
4980
+ "sprint_id",
4981
+ "sprint_name",
4982
+ "epic_link",
4983
+ "story_points"
4984
+ ]);
4985
+ const NOTION_FILTERABLE_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "multi_select", "status", "checkbox"]);
4986
+ function getJiraConfig(integration) {
4987
+ if (integration.service_type !== "JIRA") return null;
4988
+ return integration.config ?? null;
4989
+ }
4990
+ function getNotionConfig(integration) {
4991
+ if (integration.service_type !== "NOTION") return null;
4992
+ return integration.config ?? null;
4993
+ }
4994
+ function getExposedFields(config) {
4995
+ if (!(config == null ? void 0 : config.exposed_fields)) return [];
4996
+ return normalizeExposedJiraFields(
4997
+ Array.isArray(config.exposed_fields) ? config.exposed_fields : void 0
4998
+ );
4999
+ }
5000
+ function getLastKnownJiraFields(config) {
5001
+ const fields = config == null ? void 0 : config.last_known_fields;
5002
+ if (!Array.isArray(fields)) return [];
5003
+ return fields.filter(
5004
+ (field) => Boolean(field) && typeof field === "object" && typeof field.id === "string" && typeof field.name === "string"
5005
+ );
5006
+ }
5007
+ function getSelectedNotionFields(config) {
5008
+ const fields = config == null ? void 0 : config.selected_fields;
5009
+ if (!Array.isArray(fields)) return [];
5010
+ return fields.filter((field) => typeof field === "string");
5011
+ }
5012
+ function getLastKnownNotionFields(config) {
5013
+ const fields = config == null ? void 0 : config.last_known_fields;
5014
+ if (!Array.isArray(fields)) return [];
5015
+ return fields.filter(
5016
+ (field) => Boolean(field) && typeof field === "object" && typeof field.id === "string" && typeof field.name === "string" && typeof field.type === "string"
5017
+ );
5018
+ }
5019
+ const OPTION_CUSTOM_FIELD_TYPES = /* @__PURE__ */ new Set(["select", "multi_select"]);
5020
+ function getSelectableCustomFieldOptions(field) {
5021
+ var _a;
5022
+ if (!OPTION_CUSTOM_FIELD_TYPES.has(field.field_type)) return [];
5023
+ const rawOptions = (_a = field.field_config) == null ? void 0 : _a.options;
5024
+ if (!Array.isArray(rawOptions)) return [];
5025
+ return rawOptions.filter((option) => typeof option === "string" && option.trim().length > 0).map((option) => ({ label: option, value: option }));
5026
+ }
5027
+ function getJiraOptionValue(option) {
5028
+ return option.id;
5029
+ }
5030
+ function getJiraFieldFilterOptions(field) {
5031
+ const options = field.options ?? [];
5032
+ if (!options.length) return [];
5033
+ return options.map((option) => ({
5034
+ label: option.name || option.value || option.id,
5035
+ value: getJiraOptionValue(option)
5036
+ })).filter((option) => option.value.length > 0);
5037
+ }
5038
+ function getNotionFieldFilterOptions(field) {
5039
+ if (field.type === "checkbox") {
5040
+ return [
5041
+ { label: "체크됨", value: "true" },
5042
+ { label: "체크 안 됨", value: "false" }
5043
+ ];
5044
+ }
5045
+ const options = field.options ?? [];
5046
+ if (!options.length) return [];
5047
+ return options.map((option) => ({
5048
+ label: option.name,
5049
+ value: option.name
5050
+ })).filter((option) => option.value.length > 0);
5051
+ }
5052
+ function mergeOptions(current, next) {
5053
+ const byValue = new Map(current.map((option) => [option.value, option]));
5054
+ for (const option of next) {
5055
+ if (!byValue.has(option.value)) {
5056
+ byValue.set(option.value, option);
5057
+ }
5058
+ }
5059
+ return Array.from(byValue.values()).sort((a2, b) => a2.label.localeCompare(b.label));
5060
+ }
5061
+ function upsertFilterGroup(groups, group) {
5062
+ const existing = groups.get(group.id);
5063
+ if (!existing) {
5064
+ groups.set(group.id, {
5065
+ ...group,
5066
+ options: mergeOptions([], group.options)
5067
+ });
5068
+ return;
5069
+ }
5070
+ groups.set(group.id, {
5071
+ ...existing,
5072
+ options: mergeOptions(existing.options, group.options)
5073
+ });
5074
+ }
5075
+ function appendCustomFieldFilterGroups(groups, customFields) {
5076
+ for (const field of customFields) {
5077
+ const options = getSelectableCustomFieldOptions(field);
5078
+ if (!options.length) continue;
5079
+ upsertFilterGroup(groups, {
5080
+ kind: "custom",
5081
+ id: `custom:${field.id}`,
5082
+ fieldDefinitionId: field.id,
5083
+ label: field.field_name,
5084
+ options
5085
+ });
5086
+ }
5087
+ }
5088
+ function appendJiraFieldFilterGroups(groups, exposedFieldIds, fields) {
5089
+ for (const field of fields) {
5090
+ const normalizedFieldId = normalizeJiraFieldId(field.id);
5091
+ if (!exposedFieldIds.has(normalizedFieldId) || !JIRA_FILTERABLE_FIELD_IDS.has(normalizedFieldId)) {
5092
+ continue;
5093
+ }
5094
+ const options = getJiraFieldFilterOptions(field);
5095
+ if (!options.length) continue;
5096
+ upsertFilterGroup(groups, {
5097
+ kind: "jira",
5098
+ id: `jira:${normalizedFieldId}`,
5099
+ fieldName: normalizedFieldId,
5100
+ label: field.name,
5101
+ options
5102
+ });
5103
+ }
5104
+ }
5105
+ function appendNotionFieldFilterGroups(groups, selectedFields, fields) {
5106
+ for (const field of fields) {
5107
+ if (!selectedFields.has(field.id) && !selectedFields.has(field.name)) continue;
5108
+ if (!NOTION_FILTERABLE_FIELD_TYPES.has(field.type)) continue;
5109
+ const options = getNotionFieldFilterOptions(field);
5110
+ if (!options.length) continue;
5111
+ upsertFilterGroup(groups, {
5112
+ kind: "notion",
5113
+ id: `notion:${field.id}`,
5114
+ fieldName: field.name,
5115
+ label: field.name,
5116
+ options
5117
+ });
5118
+ }
5119
+ }
5120
+ function composeIssueFilterGroups(integrations, customFields) {
5121
+ const groups = /* @__PURE__ */ new Map();
5122
+ const jiraIntegration = integrations.find((integration) => {
5123
+ const config = getJiraConfig(integration);
5124
+ return integration.is_active !== false && config;
5125
+ });
5126
+ appendCustomFieldFilterGroups(groups, customFields);
5127
+ const jiraConfig = jiraIntegration ? getJiraConfig(jiraIntegration) : null;
5128
+ const configExposedFields = getExposedFields(jiraConfig);
5129
+ if (configExposedFields.length) {
5130
+ appendJiraFieldFilterGroups(
5131
+ groups,
5132
+ new Set(configExposedFields),
5133
+ getLastKnownJiraFields(jiraConfig)
5134
+ );
5135
+ }
5136
+ for (const integration of integrations) {
5137
+ if (integration.is_active === false) continue;
5138
+ const notionConfig = getNotionConfig(integration);
5139
+ if (!notionConfig) continue;
5140
+ appendNotionFieldFilterGroups(
5141
+ groups,
5142
+ new Set(getSelectedNotionFields(notionConfig)),
5143
+ getLastKnownNotionFields(notionConfig)
5144
+ );
5145
+ }
5146
+ return Array.from(groups.values()).sort((a2, b) => a2.label.localeCompare(b.label));
5147
+ }
4970
5148
  const STABLE_ATTR_KEYS = [
4971
5149
  "data-testid",
4972
5150
  "data-test",
@@ -6486,7 +6664,7 @@ var Popover$1 = (props) => {
6486
6664
  };
6487
6665
  Popover$1.displayName = POPOVER_NAME;
6488
6666
  var ANCHOR_NAME = "PopoverAnchor";
6489
- var PopoverAnchor = React.forwardRef(
6667
+ var PopoverAnchor$1 = React.forwardRef(
6490
6668
  (props, forwardedRef) => {
6491
6669
  const { __scopePopover, ...anchorProps } = props;
6492
6670
  const context = usePopoverContext(ANCHOR_NAME, __scopePopover);
@@ -6499,7 +6677,7 @@ var PopoverAnchor = React.forwardRef(
6499
6677
  return /* @__PURE__ */ jsx(Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });
6500
6678
  }
6501
6679
  );
6502
- PopoverAnchor.displayName = ANCHOR_NAME;
6680
+ PopoverAnchor$1.displayName = ANCHOR_NAME;
6503
6681
  var TRIGGER_NAME$1 = "PopoverTrigger";
6504
6682
  var PopoverTrigger$1 = React.forwardRef(
6505
6683
  (props, forwardedRef) => {
@@ -6722,11 +6900,13 @@ function getState(open) {
6722
6900
  return open ? "open" : "closed";
6723
6901
  }
6724
6902
  var Root2 = Popover$1;
6903
+ var Anchor2 = PopoverAnchor$1;
6725
6904
  var Trigger = PopoverTrigger$1;
6726
6905
  var Portal = PopoverPortal;
6727
6906
  var Content2 = PopoverContent$1;
6728
6907
  const Popover = Root2;
6729
6908
  const PopoverTrigger = Trigger;
6909
+ const PopoverAnchor = Anchor2;
6730
6910
  const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 6, onEscapeKeyDown, ...props }, ref) => {
6731
6911
  const portalContainer = usePortalContainer();
6732
6912
  return /* @__PURE__ */ jsx(Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
@@ -12786,12 +12966,6 @@ const DEFAULT_LABELS = {
12786
12966
  badge: "가이드",
12787
12967
  close: "가이드 닫기",
12788
12968
  skip: "건너뛰기",
12789
- skipConfirmTitle: "가이드를 건너뛸까요?",
12790
- // 채널마다 진입점이 다르다(admin=헤더 아이콘, extension=더보기 메뉴, sdk=FAB 메뉴).
12791
- // 위치를 특정하면 어느 한쪽에서는 틀린 안내가 되므로 라벨만 가리킨다.
12792
- skipConfirmBody: "'가이드 다시 보기'를 클릭하면 언제든 다시 열 수 있습니다.",
12793
- skipConfirmCancel: "계속 보기",
12794
- skipConfirmConfirm: "건너뛰기",
12795
12969
  previous: "이전",
12796
12970
  next: "다음",
12797
12971
  done: "완료",
@@ -13048,64 +13222,10 @@ function OnboardingPopoverContent({
13048
13222
  canGoPrevious,
13049
13223
  isLast,
13050
13224
  isVisible,
13051
- isSkipConfirmOpen,
13052
- onRequestSkip,
13053
- onCancelSkip,
13054
- onConfirmSkip,
13225
+ onSkip,
13055
13226
  onNext,
13056
13227
  onPrevious
13057
13228
  }) {
13058
- if (isSkipConfirmOpen) {
13059
- return /* @__PURE__ */ jsxs(
13060
- "div",
13061
- {
13062
- role: "alertdialog",
13063
- "aria-modal": "false",
13064
- "aria-labelledby": "issue-sticker-onboarding-skip-title",
13065
- "aria-describedby": "issue-sticker-onboarding-skip-desc",
13066
- children: [
13067
- /* @__PURE__ */ jsx(
13068
- "h2",
13069
- {
13070
- id: "issue-sticker-onboarding-skip-title",
13071
- className: "text-sm font-semibold leading-5 text-text-primary",
13072
- children: labels.skipConfirmTitle
13073
- }
13074
- ),
13075
- /* @__PURE__ */ jsx(
13076
- "p",
13077
- {
13078
- id: "issue-sticker-onboarding-skip-desc",
13079
- className: "mt-2 whitespace-pre-line text-sm leading-5 text-text-secondary",
13080
- children: labels.skipConfirmBody
13081
- }
13082
- ),
13083
- /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-end gap-2", children: [
13084
- /* @__PURE__ */ jsx(
13085
- "button",
13086
- {
13087
- type: "button",
13088
- onClick: onCancelSkip,
13089
- disabled: !isVisible,
13090
- 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",
13091
- children: labels.skipConfirmCancel
13092
- }
13093
- ),
13094
- /* @__PURE__ */ jsx(
13095
- "button",
13096
- {
13097
- type: "button",
13098
- onClick: onConfirmSkip,
13099
- disabled: !isVisible,
13100
- 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",
13101
- children: labels.skipConfirmConfirm
13102
- }
13103
- )
13104
- ] })
13105
- ]
13106
- }
13107
- );
13108
- }
13109
13229
  const hasNextButton = shouldRenderNextButton(step);
13110
13230
  return /* @__PURE__ */ jsxs("div", { children: [
13111
13231
  /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold leading-5 text-text-primary", children: step.title }),
@@ -13134,7 +13254,7 @@ function OnboardingPopoverContent({
13134
13254
  "button",
13135
13255
  {
13136
13256
  type: "button",
13137
- onClick: onRequestSkip,
13257
+ onClick: onSkip,
13138
13258
  disabled: !isVisible,
13139
13259
  className: LINK_BUTTON_CLASS,
13140
13260
  children: labels.skip
@@ -13145,7 +13265,7 @@ function OnboardingPopoverContent({
13145
13265
  {
13146
13266
  type: "button",
13147
13267
  onClick: onPrevious,
13148
- disabled: !isVisible || isSkipConfirmOpen,
13268
+ disabled: !isVisible,
13149
13269
  className: LINK_BUTTON_CLASS,
13150
13270
  children: labels.previous
13151
13271
  }
@@ -13157,7 +13277,7 @@ function OnboardingPopoverContent({
13157
13277
  {
13158
13278
  type: "button",
13159
13279
  onClick: onPrevious,
13160
- disabled: !isVisible || isSkipConfirmOpen,
13280
+ disabled: !isVisible,
13161
13281
  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",
13162
13282
  children: labels.previous
13163
13283
  }
@@ -13167,7 +13287,7 @@ function OnboardingPopoverContent({
13167
13287
  {
13168
13288
  type: "button",
13169
13289
  onClick: onNext,
13170
- disabled: !isVisible || isSkipConfirmOpen,
13290
+ disabled: !isVisible,
13171
13291
  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",
13172
13292
  children: isLast ? labels.done : step.nextLabel ?? labels.next
13173
13293
  }
@@ -13181,6 +13301,7 @@ function OnboardingOverlay({
13181
13301
  targetRect,
13182
13302
  targetRadius,
13183
13303
  avoidRects,
13304
+ affordanceRect,
13184
13305
  elevateHighlight,
13185
13306
  allowSkip = true,
13186
13307
  className,
@@ -13194,13 +13315,29 @@ function OnboardingOverlay({
13194
13315
  }) {
13195
13316
  const maskId = React.useId().replace(/:/g, "");
13196
13317
  const renderHighlight = (node) => elevateHighlight && typeof document !== "undefined" ? ReactDOM.createPortal(node, document.body) : node;
13197
- const [isSkipConfirmOpen, setIsSkipConfirmOpen] = React.useState(false);
13198
13318
  const cutoutRect = targetRect ? padRect(targetRect, MASK_PADDING) : null;
13199
13319
  const cutoutRadius = cutoutRect ? Math.min(
13200
13320
  targetRadius === null || targetRadius === void 0 ? CUTOUT_RADIUS : targetRadius + MASK_PADDING,
13201
13321
  cutoutRect.width / 2,
13202
13322
  cutoutRect.height / 2
13203
13323
  ) : 0;
13324
+ const hasAffordanceTarget = !!step.affordanceTargetId;
13325
+ const affordanceCutout = affordanceRect ? padRect(affordanceRect, MASK_PADDING) : null;
13326
+ const affordanceDiameter = affordanceRect ? Math.max(affordanceRect.width, affordanceRect.height) + MASK_PADDING * 2 : 0;
13327
+ const affordanceCircle = affordanceRect ? (() => {
13328
+ const centerX = (affordanceRect.left + affordanceRect.right) / 2;
13329
+ const centerY = (affordanceRect.top + affordanceRect.bottom) / 2;
13330
+ const radius = affordanceDiameter / 2;
13331
+ return {
13332
+ left: centerX - radius,
13333
+ top: centerY - radius,
13334
+ right: centerX + radius,
13335
+ bottom: centerY + radius,
13336
+ width: affordanceDiameter,
13337
+ height: affordanceDiameter
13338
+ };
13339
+ })() : null;
13340
+ const popoverAnchorRect = hasAffordanceTarget && affordanceCutout ? affordanceCutout : cutoutRect;
13204
13341
  const popoverRef = React.useRef(null);
13205
13342
  const [popoverSize, setPopoverSize] = React.useState(
13206
13343
  null
@@ -13219,23 +13356,23 @@ function OnboardingOverlay({
13219
13356
  const observer = new ResizeObserver(measure);
13220
13357
  observer.observe(element);
13221
13358
  return () => observer.disconnect();
13222
- }, [step.id, step.body, isSkipConfirmOpen]);
13359
+ }, [step.id, step.body]);
13223
13360
  const effectiveSize = popoverSize && popoverSize.width > 0 && popoverSize.height > 0 ? popoverSize : DEFAULT_POPOVER_SIZE;
13224
13361
  const placement = resolvePopoverPlacement(
13225
- step.position ?? (cutoutRect ? "bottom" : "center"),
13226
- cutoutRect ?? getViewportRect(),
13362
+ step.position ?? (popoverAnchorRect ? "bottom" : "center"),
13363
+ popoverAnchorRect ?? getViewportRect(),
13227
13364
  effectiveSize,
13228
- cutoutRect ? avoidRects ?? [] : []
13365
+ popoverAnchorRect ? avoidRects ?? [] : []
13229
13366
  );
13230
13367
  const { left: popoverLeft, top: popoverTop } = placement;
13231
- const shouldCenterPopover = !cutoutRect && (step.position ?? "center") === "center";
13368
+ const shouldCenterPopover = !popoverAnchorRect && (step.position ?? "center") === "center";
13232
13369
  const maskColor = isTargetInteractionStep(step) ? "rgba(8, 13, 18, 0.74)" : "rgba(8, 13, 18, 0.62)";
13233
13370
  const isPassthrough = !!step.advanceOn;
13234
13371
  const isTargetInteraction = isTargetInteractionStep(step);
13235
13372
  const clickHint = isTargetInteraction ? step.clickHint ?? labels.clickHint : null;
13236
- React.useEffect(() => {
13237
- setIsSkipConfirmOpen(false);
13238
- }, [step.id]);
13373
+ const isCutoutInteractionStyled = isTargetInteraction && !hasAffordanceTarget;
13374
+ const showAffordanceEmphasis = isTargetInteraction && hasAffordanceTarget && !!affordanceCircle;
13375
+ const ringCursorRect = !isTargetInteraction ? null : hasAffordanceTarget ? affordanceCircle : cutoutRect;
13239
13376
  return /* @__PURE__ */ jsxs(
13240
13377
  "div",
13241
13378
  {
@@ -13328,7 +13465,7 @@ function OnboardingOverlay({
13328
13465
  "data-testid": "onboarding-cutout-outline",
13329
13466
  className: cn(
13330
13467
  "issue-sticker-onboarding-highlight fixed",
13331
- isTargetInteraction ? "border-2 border-brand" : "border border-white/90"
13468
+ isCutoutInteractionStyled ? "border-2 border-brand" : "border border-white/90"
13332
13469
  ),
13333
13470
  style: {
13334
13471
  left: cutoutRect.left,
@@ -13343,7 +13480,31 @@ function OnboardingOverlay({
13343
13480
  step.id
13344
13481
  )
13345
13482
  ) : null,
13346
- cutoutRect && isTargetInteraction ? renderHighlight(
13483
+ showAffordanceEmphasis && affordanceCircle ? renderHighlight(
13484
+ /* 강조(컷아웃)와 클릭 유도 위치가 분리된 단계의 브랜드 링. 컷아웃 테두리는
13485
+ * 위에서 이미 순수 강조 스타일로 그렸으니, 여기서는 실제로 눌러야 할 요소
13486
+ * 중심에 원을 그린다 — 사각형 컷아웃과 구별돼야 "강조 대상이 아니라 이걸
13487
+ * 누르라"는 뜻이 선다. */
13488
+ /* @__PURE__ */ jsx(
13489
+ "div",
13490
+ {
13491
+ "aria-hidden": "true",
13492
+ "data-testid": "onboarding-affordance-ring",
13493
+ className: "issue-sticker-onboarding-highlight fixed rounded-full border-2 border-brand",
13494
+ style: {
13495
+ left: affordanceCircle.left,
13496
+ top: affordanceCircle.top,
13497
+ width: affordanceCircle.width,
13498
+ height: affordanceCircle.height,
13499
+ borderRadius: 9999,
13500
+ pointerEvents: "none",
13501
+ zIndex: elevateHighlight ? OVERLAY_LAYER_INDEX.runtimeHost : void 0
13502
+ }
13503
+ },
13504
+ `${step.id}-affordance`
13505
+ )
13506
+ ) : null,
13507
+ ringCursorRect ? renderHighlight(
13347
13508
  /* 클릭하는 커서. 테두리만으로는 "봐야 할 곳"까지만 전달되고 "클릭하라"가
13348
13509
  * 전달되지 않는다. 손 모양 반복 동작이 그 자리를 맡는다. */
13349
13510
  /* @__PURE__ */ jsxs(
@@ -13353,8 +13514,8 @@ function OnboardingOverlay({
13353
13514
  "data-testid": "onboarding-cutout-cursor",
13354
13515
  className: "issue-sticker-onboarding-tap fixed",
13355
13516
  style: {
13356
- left: cutoutRect.right - TAP_INSET,
13357
- top: cutoutRect.bottom - TAP_INSET,
13517
+ left: ringCursorRect.right - TAP_INSET,
13518
+ top: ringCursorRect.bottom - TAP_INSET,
13358
13519
  pointerEvents: "none",
13359
13520
  zIndex: elevateHighlight ? OVERLAY_LAYER_INDEX.runtimeHost : void 0
13360
13521
  },
@@ -13378,7 +13539,6 @@ function OnboardingOverlay({
13378
13539
  }
13379
13540
  )
13380
13541
  ) : null,
13381
- isSkipConfirmOpen ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "fixed inset-0 pointer-events-auto" }) : null,
13382
13542
  renderHighlight(
13383
13543
  /* @__PURE__ */ jsx(
13384
13544
  "div",
@@ -13405,10 +13565,7 @@ function OnboardingOverlay({
13405
13565
  canGoPrevious,
13406
13566
  isLast,
13407
13567
  isVisible: isPopoverVisible,
13408
- isSkipConfirmOpen,
13409
- onRequestSkip: () => setIsSkipConfirmOpen(true),
13410
- onCancelSkip: () => setIsSkipConfirmOpen(false),
13411
- onConfirmSkip: onSkip,
13568
+ onSkip,
13412
13569
  onNext,
13413
13570
  onPrevious
13414
13571
  }
@@ -13595,18 +13752,24 @@ function OnboardingProvider({
13595
13752
  () => activeTargetIds.map((id) => targetMapRef.current.get(id) ?? null).filter((el) => el !== null),
13596
13753
  [activeTargetIds]
13597
13754
  );
13755
+ const activeAffordanceTargetId = activeStep == null ? void 0 : activeStep.affordanceTargetId;
13756
+ const getObservedElements = React.useCallback(() => {
13757
+ const elements = getActiveTargetElements();
13758
+ const affordanceElement = activeAffordanceTargetId ? targetMapRef.current.get(activeAffordanceTargetId) ?? null : null;
13759
+ return affordanceElement ? [...elements, affordanceElement] : elements;
13760
+ }, [activeAffordanceTargetId, getActiveTargetElements]);
13598
13761
  const scheduleLayoutUpdate = React.useCallback(() => {
13599
13762
  clearLayoutFrame();
13600
13763
  frameRef.current = window.requestAnimationFrame(() => {
13601
13764
  frameRef.current = null;
13602
13765
  const nextRect = unionRect(
13603
- getActiveTargetElements().map(getElementRect).filter((r2) => r2 !== null)
13766
+ getObservedElements().map(getElementRect).filter((r2) => r2 !== null)
13604
13767
  );
13605
13768
  if (areRectsEqual(lastRectRef.current, nextRect)) return;
13606
13769
  lastRectRef.current = nextRect;
13607
13770
  setLayoutVersion((version2) => version2 + 1);
13608
13771
  });
13609
- }, [clearLayoutFrame, getActiveTargetElements]);
13772
+ }, [clearLayoutFrame, getObservedElements]);
13610
13773
  const openAtStep = React.useCallback(
13611
13774
  (stepIndex) => {
13612
13775
  var _a;
@@ -13764,7 +13927,7 @@ function OnboardingProvider({
13764
13927
  }, [activeStep, advanceFromTargetClick, goToStep, isActiveRoute, isOpen]);
13765
13928
  React.useEffect(() => {
13766
13929
  if (!isOpen || !isActiveRoute) return;
13767
- const elements = getActiveTargetElements();
13930
+ const elements = getObservedElements();
13768
13931
  if (elements.length === 0) return;
13769
13932
  scheduleLayoutUpdate();
13770
13933
  window.addEventListener("resize", scheduleLayoutUpdate);
@@ -13779,7 +13942,7 @@ function OnboardingProvider({
13779
13942
  };
13780
13943
  }, [
13781
13944
  clearLayoutFrame,
13782
- getActiveTargetElements,
13945
+ getObservedElements,
13783
13946
  isActiveRoute,
13784
13947
  isOpen,
13785
13948
  scheduleLayoutUpdate,
@@ -13792,6 +13955,7 @@ function OnboardingProvider({
13792
13955
  const targetRect = isOpen && isActiveRoute && allTargetsResolved ? unionRect(resolvedTargetRects.filter((r2) => r2 !== null)) : null;
13793
13956
  const targetRadius = activeTargetIds.length === 1 ? getElementRadius(targetMapRef.current.get(activeTargetIds[0]) ?? null) : null;
13794
13957
  const avoidRects = ((activeStep == null ? void 0 : activeStep.avoidTargetIds) ?? []).map((id) => getElementRect(targetMapRef.current.get(id) ?? null)).filter((rect) => rect !== null);
13958
+ const affordanceRect = (activeStep == null ? void 0 : activeStep.affordanceTargetId) ? getElementRect(targetMapRef.current.get(activeStep.affordanceTargetId) ?? null) : null;
13795
13959
  const shouldRenderOverlay = isOpen && activeStep && isActiveRoute && !suppressed && !activeStep.silent && (!stepHasTarget || targetRect);
13796
13960
  const isTargetReady = !stepHasTarget || targetRect !== null;
13797
13961
  React.useEffect(() => {
@@ -13844,6 +14008,7 @@ function OnboardingProvider({
13844
14008
  targetRect,
13845
14009
  targetRadius,
13846
14010
  avoidRects,
14011
+ affordanceRect,
13847
14012
  elevateHighlight,
13848
14013
  allowSkip,
13849
14014
  className,
@@ -14073,49 +14238,49 @@ function buildExternalUserPayload(user) {
14073
14238
  };
14074
14239
  }
14075
14240
  export {
14076
- DatePicker as $,
14077
- createSafeLogBackup as A,
14078
- getLogBackupSessionId as B,
14241
+ getNotionPageMetadata as $,
14242
+ getLogBackupSessionId as A,
14243
+ createIndexedDbLogBackup as B,
14079
14244
  ConsoleCollector as C,
14080
- createIndexedDbLogBackup as D,
14081
- PopoverTrigger as E,
14082
- Input as F,
14083
- PopoverContent as G,
14084
- Select$1 as H,
14245
+ PopoverTrigger as D,
14246
+ Input as E,
14247
+ PopoverContent as F,
14248
+ Select$1 as G,
14249
+ SelectTrigger as H,
14085
14250
  ISSUE_STICKER_INTERNAL_LOG_PREFIX as I,
14086
- SelectTrigger as J,
14087
- SelectValue as K,
14251
+ SelectValue as J,
14252
+ SelectContent as K,
14088
14253
  Label as L,
14089
- SelectContent as M,
14254
+ SelectItem as M,
14090
14255
  NetworkCollector as N,
14091
- SelectItem as O,
14256
+ getJiraMetadata as O,
14092
14257
  Popover as P,
14093
- getJiraMetadata as Q,
14094
- buildJiraIssueFields as R,
14258
+ buildJiraIssueFields as Q,
14259
+ Button$1 as R,
14095
14260
  ScreenRecordingController as S,
14096
- Button$1 as T,
14097
- Root2 as U,
14098
- Trigger as V,
14099
- ChevronDown as W,
14100
- Portal as X,
14101
- Content2 as Y,
14102
- Check as Z,
14103
- X as _,
14261
+ Root2 as T,
14262
+ Trigger as U,
14263
+ ChevronDown as V,
14264
+ Portal as W,
14265
+ Content2 as X,
14266
+ Check as Y,
14267
+ X as Z,
14268
+ DatePicker as _,
14104
14269
  uploadSignedMediaWithApi as a,
14105
- getNotionPageMetadata as a0,
14106
- buildNotionFieldViews as a1,
14107
- DirectUploadError as a2,
14108
- toast as a3,
14109
- getSnapshot as a4,
14110
- subscribe as a5,
14111
- getRegisteredUploadId as a6,
14112
- ChevronRight as a7,
14113
- ReactRemoveScroll as a8,
14114
- hideOthers as a9,
14115
- useFocusGuards as aa,
14116
- FocusScope as ab,
14117
- getExposedJiraFields as ac,
14118
- isJiraFieldExposed as ad,
14270
+ buildNotionFieldViews as a0,
14271
+ DirectUploadError as a1,
14272
+ toast as a2,
14273
+ getSnapshot as a3,
14274
+ subscribe as a4,
14275
+ getRegisteredUploadId as a5,
14276
+ ChevronRight as a6,
14277
+ ReactRemoveScroll as a7,
14278
+ hideOthers as a8,
14279
+ useFocusGuards as a9,
14280
+ FocusScope as aa,
14281
+ getExposedJiraFields as ab,
14282
+ isJiraFieldExposed as ac,
14283
+ normalizeExposedJiraFields as ad,
14119
14284
  getPrimaryJiraMapping as ae,
14120
14285
  createCollection as af,
14121
14286
  useDirection as ag,
@@ -14126,29 +14291,30 @@ export {
14126
14291
  OnboardingProvider as al,
14127
14292
  useOnboardingTarget as am,
14128
14293
  useOnboardingFlow as an,
14129
- normalizeJiraFieldId as b,
14294
+ PopoverAnchor as ao,
14295
+ buildJiraCreateFields as b,
14130
14296
  captureWithModernScreenshot as c,
14131
14297
  directUploadToSignedUrl as d,
14132
- buildJiraCreateFields as e,
14133
- buildNotionCreateFields as f,
14298
+ buildNotionCreateFields as e,
14299
+ buildGuestOwnerQuery as f,
14134
14300
  getElementPosition as g,
14135
- buildGuestOwnerQuery as h,
14301
+ composeIssueFilterGroups as h,
14136
14302
  buildIssueIntegrationsPayload as i,
14137
14303
  devLogger as j,
14138
14304
  filterExcludeServiceRelatedLogs as k,
14139
14305
  filterExcludeServiceRelatedConsoleLogs as l,
14140
14306
  compactNetworkLogsForTransport as m,
14141
- normalizeExposedJiraFields as n,
14142
- CONSOLE_LOG_SUBMIT_LIMIT as o,
14307
+ CONSOLE_LOG_SUBMIT_LIMIT as n,
14308
+ buildExternalUserPayload as o,
14143
14309
  pristineFetch as p,
14144
- buildExternalUserPayload as q,
14145
- shrinkNetworkLogsToFit as r,
14310
+ shrinkNetworkLogsToFit as q,
14311
+ measureJsonBytes as r,
14146
14312
  selectNetworkLogsForSubmit as s,
14147
- measureJsonBytes as t,
14313
+ sanitizeString as t,
14148
14314
  uploadScreenshotDataUrls as u,
14149
- sanitizeString as v,
14150
- getCurrentPageUrl as w,
14151
- SessionReplayCaptureController as x,
14152
- preloadModernScreenshot as y,
14153
- trimLogBackupPayload as z
14315
+ getCurrentPageUrl as v,
14316
+ SessionReplayCaptureController as w,
14317
+ preloadModernScreenshot as x,
14318
+ trimLogBackupPayload as y,
14319
+ createSafeLogBackup as z
14154
14320
  };