@solhun/feedback-kit-core 0.6.0 → 0.7.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.
package/dist/index.d.cts CHANGED
@@ -1173,7 +1173,7 @@ declare class ReportModalController {
1173
1173
  /** 지금 들고 있는 핀의 기준. 핀이 없으면 의미 없다(기본 `picture`). */
1174
1174
  private pinAnchor;
1175
1175
  /**
1176
- * 사용자가 [제안 ▾] 를 직접 건드렸는가(방향 무관). 한 번이라도 건드리면 이후
1176
+ * 사용자가 [이런 건가요? ▾] 를 직접 건드렸는가(방향 무관). 한 번이라도 건드리면 이후
1177
1177
  * 타이핑에 의한 자동 접힘/펼침이 멈춘다 — "사람이 편 상태는 모달이 닫힐 때까지 유지"를
1178
1178
  * 이렇게 구현한다. `open()` 에서 매번 리셋된다.
1179
1179
  */
@@ -1205,8 +1205,23 @@ declare class ReportModalController {
1205
1205
  confirmClose(): void;
1206
1206
  /** 확인 대화에서 "계속 쓰기"를 고른 경우. 입력은 그대로 남는다. */
1207
1207
  cancelClose(): void;
1208
- /** 확인 없이 닫는다(요소 지목 모드로 넘어갈 때처럼 흐름이 이어지는 경우). */
1208
+ /**
1209
+ * 확인 없이 닫는다(요소 지목 모드로 넘어갈 때처럼 흐름이 이어지는 경우).
1210
+ *
1211
+ * **쓰던 글은 남긴다.** 지목으로 넘어가는 건 이 제보를 버린 게 아니라 "가리킬 요소를
1212
+ * 고르러 나간" 것이다. 예전엔 여기서 코멘트를 통째로 비웠고, 그래서 모달에 몇 줄 써 놓고
1213
+ * [요소 지목 모드]를 켜면 **확인도 없이 글이 사라졌다** — 사용자가 직접 닫을 때
1214
+ * (`requestClose`)는 확인을 받는데 이 경로만 안 받았다.
1215
+ *
1216
+ * 그림과 좌표는 남기지 않는다. 지목하러 간다는 건 **어느 화면의 무엇을 가리킬지 다시
1217
+ * 정한다**는 뜻이라, 그때의 캡처와 핀은 다음 화면에서 새로 잡는 게 맞다.
1218
+ */
1209
1219
  dismiss(): void;
1220
+ /**
1221
+ * @param opts.keepResult 전송 결과까지 통째로 보존한다(대기 중 제보 복원용).
1222
+ * @param opts.keepText 사람이 입력한 것(코멘트·우선순위)만 보존한다. 그림·좌표·전송
1223
+ * 상태는 평소처럼 비운다.
1224
+ */
1210
1225
  private close;
1211
1226
  /** 상한을 넘겨도 값을 자르지 않는다. 거부는 하되 사용자가 쓴 글은 보존한다. */
1212
1227
  setComment(value: string): void;
@@ -1245,7 +1260,7 @@ declare class ReportModalController {
1245
1260
  * 쓴 글을 지우지 않는다.
1246
1261
  */
1247
1262
  applyHint(hintId: string): void;
1248
- /** [제안 ▾] 토글. 방향과 무관하게 이후 자동 접힘/펼침을 멈춘다(`userToggledHints`). */
1263
+ /** [이런 건가요? ▾] 토글. 방향과 무관하게 이후 자동 접힘/펼침을 멈춘다(`userToggledHints`). */
1249
1264
  toggleHints(): void;
1250
1265
  tabNext(): string | null;
1251
1266
  tabPrev(): string | null;
package/dist/index.d.ts CHANGED
@@ -1173,7 +1173,7 @@ declare class ReportModalController {
1173
1173
  /** 지금 들고 있는 핀의 기준. 핀이 없으면 의미 없다(기본 `picture`). */
1174
1174
  private pinAnchor;
1175
1175
  /**
1176
- * 사용자가 [제안 ▾] 를 직접 건드렸는가(방향 무관). 한 번이라도 건드리면 이후
1176
+ * 사용자가 [이런 건가요? ▾] 를 직접 건드렸는가(방향 무관). 한 번이라도 건드리면 이후
1177
1177
  * 타이핑에 의한 자동 접힘/펼침이 멈춘다 — "사람이 편 상태는 모달이 닫힐 때까지 유지"를
1178
1178
  * 이렇게 구현한다. `open()` 에서 매번 리셋된다.
1179
1179
  */
@@ -1205,8 +1205,23 @@ declare class ReportModalController {
1205
1205
  confirmClose(): void;
1206
1206
  /** 확인 대화에서 "계속 쓰기"를 고른 경우. 입력은 그대로 남는다. */
1207
1207
  cancelClose(): void;
1208
- /** 확인 없이 닫는다(요소 지목 모드로 넘어갈 때처럼 흐름이 이어지는 경우). */
1208
+ /**
1209
+ * 확인 없이 닫는다(요소 지목 모드로 넘어갈 때처럼 흐름이 이어지는 경우).
1210
+ *
1211
+ * **쓰던 글은 남긴다.** 지목으로 넘어가는 건 이 제보를 버린 게 아니라 "가리킬 요소를
1212
+ * 고르러 나간" 것이다. 예전엔 여기서 코멘트를 통째로 비웠고, 그래서 모달에 몇 줄 써 놓고
1213
+ * [요소 지목 모드]를 켜면 **확인도 없이 글이 사라졌다** — 사용자가 직접 닫을 때
1214
+ * (`requestClose`)는 확인을 받는데 이 경로만 안 받았다.
1215
+ *
1216
+ * 그림과 좌표는 남기지 않는다. 지목하러 간다는 건 **어느 화면의 무엇을 가리킬지 다시
1217
+ * 정한다**는 뜻이라, 그때의 캡처와 핀은 다음 화면에서 새로 잡는 게 맞다.
1218
+ */
1209
1219
  dismiss(): void;
1220
+ /**
1221
+ * @param opts.keepResult 전송 결과까지 통째로 보존한다(대기 중 제보 복원용).
1222
+ * @param opts.keepText 사람이 입력한 것(코멘트·우선순위)만 보존한다. 그림·좌표·전송
1223
+ * 상태는 평소처럼 비운다.
1224
+ */
1210
1225
  private close;
1211
1226
  /** 상한을 넘겨도 값을 자르지 않는다. 거부는 하되 사용자가 쓴 글은 보존한다. */
1212
1227
  setComment(value: string): void;
@@ -1245,7 +1260,7 @@ declare class ReportModalController {
1245
1260
  * 쓴 글을 지우지 않는다.
1246
1261
  */
1247
1262
  applyHint(hintId: string): void;
1248
- /** [제안 ▾] 토글. 방향과 무관하게 이후 자동 접힘/펼침을 멈춘다(`userToggledHints`). */
1263
+ /** [이런 건가요? ▾] 토글. 방향과 무관하게 이후 자동 접힘/펼침을 멈춘다(`userToggledHints`). */
1249
1264
  toggleHints(): void;
1250
1265
  tabNext(): string | null;
1251
1266
  tabPrev(): string | null;
package/dist/index.js CHANGED
@@ -1364,7 +1364,7 @@ var ReportModalController = class {
1364
1364
  /** 지금 들고 있는 핀의 기준. 핀이 없으면 의미 없다(기본 `picture`). */
1365
1365
  this.pinAnchor = "picture";
1366
1366
  /**
1367
- * 사용자가 [제안 ▾] 를 직접 건드렸는가(방향 무관). 한 번이라도 건드리면 이후
1367
+ * 사용자가 [이런 건가요? ▾] 를 직접 건드렸는가(방향 무관). 한 번이라도 건드리면 이후
1368
1368
  * 타이핑에 의한 자동 접힘/펼침이 멈춘다 — "사람이 편 상태는 모달이 닫힐 때까지 유지"를
1369
1369
  * 이렇게 구현한다. `open()` 에서 매번 리셋된다.
1370
1370
  */
@@ -1454,13 +1454,13 @@ var ReportModalController = class {
1454
1454
  this.submitAttempted = false;
1455
1455
  this.pinAnchor = opts.pin && !pendingReport ? "viewport" : "picture";
1456
1456
  this.userToggledHints = false;
1457
- const resolvedComment = pendingReport?.comment ?? "";
1457
+ const resolvedComment = pendingReport?.comment ?? this.state.comment;
1458
1458
  this.patch({
1459
1459
  open: true,
1460
1460
  comment: resolvedComment,
1461
1461
  // 요소를 지목해서 연 경우엔 그 요소를 물고 간다. 대기 항목 복원이 우선이다.
1462
1462
  element: pendingReport?.element ?? opts.element ?? null,
1463
- priority: pendingReport?.priority ?? "unset",
1463
+ priority: pendingReport?.priority ?? this.state.priority,
1464
1464
  screenshot: pendingReport?.screenshot ?? null,
1465
1465
  screenshotStatus: "none",
1466
1466
  screenshotMessage: null,
@@ -1497,16 +1497,32 @@ var ReportModalController = class {
1497
1497
  cancelClose() {
1498
1498
  this.patch({ closeConfirmVisible: false });
1499
1499
  }
1500
- /** 확인 없이 닫는다(요소 지목 모드로 넘어갈 때처럼 흐름이 이어지는 경우). */
1500
+ /**
1501
+ * 확인 없이 닫는다(요소 지목 모드로 넘어갈 때처럼 흐름이 이어지는 경우).
1502
+ *
1503
+ * **쓰던 글은 남긴다.** 지목으로 넘어가는 건 이 제보를 버린 게 아니라 "가리킬 요소를
1504
+ * 고르러 나간" 것이다. 예전엔 여기서 코멘트를 통째로 비웠고, 그래서 모달에 몇 줄 써 놓고
1505
+ * [요소 지목 모드]를 켜면 **확인도 없이 글이 사라졌다** — 사용자가 직접 닫을 때
1506
+ * (`requestClose`)는 확인을 받는데 이 경로만 안 받았다.
1507
+ *
1508
+ * 그림과 좌표는 남기지 않는다. 지목하러 간다는 건 **어느 화면의 무엇을 가리킬지 다시
1509
+ * 정한다**는 뜻이라, 그때의 캡처와 핀은 다음 화면에서 새로 잡는 게 맞다.
1510
+ */
1501
1511
  dismiss() {
1502
- this.close();
1512
+ this.close({ keepText: true });
1503
1513
  }
1514
+ /**
1515
+ * @param opts.keepResult 전송 결과까지 통째로 보존한다(대기 중 제보 복원용).
1516
+ * @param opts.keepText 사람이 입력한 것(코멘트·우선순위)만 보존한다. 그림·좌표·전송
1517
+ * 상태는 평소처럼 비운다.
1518
+ */
1504
1519
  close(opts) {
1505
1520
  this.captureGeneration += 1;
1506
1521
  const keepDraft = opts?.keepResult || this.state.submitStatus === "pending";
1522
+ const keepText = keepDraft || opts?.keepText === true;
1507
1523
  const cleared = keepDraft ? {} : {
1508
- comment: "",
1509
- priority: "unset",
1524
+ comment: keepText ? this.state.comment : "",
1525
+ priority: keepText ? this.state.priority : "unset",
1510
1526
  screenshot: null,
1511
1527
  screenshotStatus: "none",
1512
1528
  screenshotMessage: null,
@@ -1648,7 +1664,7 @@ ${hint.draft}`;
1648
1664
  ...this.hintsPatchFor(comment)
1649
1665
  });
1650
1666
  }
1651
- /** [제안 ▾] 토글. 방향과 무관하게 이후 자동 접힘/펼침을 멈춘다(`userToggledHints`). */
1667
+ /** [이런 건가요? ▾] 토글. 방향과 무관하게 이후 자동 접힘/펼침을 멈춘다(`userToggledHints`). */
1652
1668
  toggleHints() {
1653
1669
  this.userToggledHints = true;
1654
1670
  this.patch({ hintsExpanded: !this.state.hintsExpanded });
@@ -2583,6 +2599,8 @@ function parseHintItem(item) {
2583
2599
  const scope = obj.scope;
2584
2600
  const platforms = parsePlatforms(obj.platforms);
2585
2601
  if (platforms === null) return null;
2602
+ const element = parseElementRule(obj.element);
2603
+ if (element === MALFORMED_ELEMENT_RULE) return null;
2586
2604
  return {
2587
2605
  id,
2588
2606
  label,
@@ -2590,7 +2608,7 @@ function parseHintItem(item) {
2590
2608
  scope,
2591
2609
  platforms,
2592
2610
  paths: parsePaths(obj.paths),
2593
- element: parseElementRule(obj.element),
2611
+ element,
2594
2612
  active: parseActive(obj.active)
2595
2613
  };
2596
2614
  }
@@ -2610,19 +2628,18 @@ function parsePaths(value) {
2610
2628
  if (!Array.isArray(value)) return [];
2611
2629
  return value.filter((p) => typeof p === "string");
2612
2630
  }
2631
+ var MALFORMED_ELEMENT_RULE = /* @__PURE__ */ Symbol("malformed-element-rule");
2613
2632
  function parseElementRule(value) {
2614
2633
  if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
2615
2634
  const obj = value;
2616
2635
  const rule = {};
2617
- if (Array.isArray(obj.tags)) rule.tags = obj.tags.filter((v) => typeof v === "string");
2618
- if (Array.isArray(obj.roles)) rule.roles = obj.roles.filter((v) => typeof v === "string");
2619
- if (Array.isArray(obj.classIncludes)) {
2620
- rule.classIncludes = obj.classIncludes.filter((v) => typeof v === "string");
2621
- }
2622
- if (Array.isArray(obj.componentIncludes)) {
2623
- rule.componentIncludes = obj.componentIncludes.filter((v) => typeof v === "string");
2636
+ const axes = ["tags", "roles", "classIncludes", "componentIncludes", "testIds"];
2637
+ for (const axis of axes) {
2638
+ if (!(axis in obj)) continue;
2639
+ const axisValue = obj[axis];
2640
+ if (!Array.isArray(axisValue)) return MALFORMED_ELEMENT_RULE;
2641
+ rule[axis] = axisValue.filter((v) => typeof v === "string");
2624
2642
  }
2625
- if (Array.isArray(obj.testIds)) rule.testIds = obj.testIds.filter((v) => typeof v === "string");
2626
2643
  return rule;
2627
2644
  }
2628
2645
  function nonEmptyString(value) {