lite-questionnaire 1.0.3 → 1.0.5

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/README.md CHANGED
@@ -376,5 +376,12 @@ lite-questionnaire/
376
376
  │ └── rating.ts # 评分滑块 + 表情渲染
377
377
  ├── design/
378
378
  │ └── questionnaire-openapi.yaml
379
+ ├── image/
380
+ ├── skills/
381
+ │ └── lite-questionnaire/
382
+ │ └── SKILL.md
383
+ ├── .gitignore
384
+ ├── LICENSE
385
+ ├── package.json
379
386
  └── README.md
380
387
  ```
package/input.ts CHANGED
@@ -256,20 +256,33 @@ export function createInputHandler(
256
256
  if (q.type === "confirm") {
257
257
  if (matchesKey(data, Key.left)) {
258
258
  const state = core.getUIState();
259
- state.confirmValue = true;
259
+ state.optionIndex = 0; // 光标移到「是」
260
260
  core.saveUIState(state);
261
261
  onUpdate();
262
262
  return;
263
263
  }
264
264
  if (matchesKey(data, Key.right)) {
265
265
  const state = core.getUIState();
266
- state.confirmValue = false;
266
+ state.optionIndex = 1; // 光标移到「否」
267
+ core.saveUIState(state);
268
+ onUpdate();
269
+ return;
270
+ }
271
+ if (matchesKey(data, Key.space)) {
272
+ const state = core.getUIState();
273
+ state.confirmValue = state.optionIndex === 0; // ● 移到光标位置
267
274
  core.saveUIState(state);
268
275
  onUpdate();
269
276
  return;
270
277
  }
271
278
  if (matchesKey(data, Key.enter)) {
272
- advance();
279
+ const state = core.getUIState();
280
+ state.confirmValue = state.optionIndex === 0; // 确认选中
281
+ core.saveUIState(state);
282
+ core.inputMode = false;
283
+ core.inputQuestionId = null;
284
+ saveFn();
285
+ onUpdate();
273
286
  return;
274
287
  }
275
288
  return;
@@ -492,7 +505,23 @@ export function createInputHandler(
492
505
  return;
493
506
  }
494
507
 
495
- case "confirm":
508
+ case "confirm": {
509
+ if (matchesKey(data, Key.tab)) {
510
+ core.inputMode = true;
511
+ core.inputQuestionId = q.id;
512
+ // 进入选择态时,光标初始位置与当前 ● 一致
513
+ const state = core.getUIState();
514
+ state.optionIndex = state.confirmValue ? 0 : 1;
515
+ core.saveUIState(state);
516
+ onUpdate();
517
+ return;
518
+ }
519
+ if (matchesKey(data, Key.enter)) {
520
+ advance();
521
+ return;
522
+ }
523
+ break;
524
+ }
496
525
  case "rating": {
497
526
  if (matchesKey(data, Key.tab)) {
498
527
  core.inputMode = true;
@@ -25,18 +25,27 @@ export function renderConfirmQuestion(
25
25
  const noLabel = q.noLabel || "否";
26
26
  const selectedYes = state.confirmValue === true;
27
27
 
28
- // 渲染两个按钮
29
- const yesBtn = selectedYes
28
+ // 是否处于选择态(Tab 进入的编辑模式)
29
+ const isEditing = core.inputMode && core.inputQuestionId === q.id;
30
+ // 选择态下光标位置:optionIndex=0 表示在「是」,1 表示在「否」
31
+ const cursorOnYes = isEditing && state.optionIndex === 0;
32
+ const cursorOnNo = isEditing && state.optionIndex === 1;
33
+
34
+ // 渲染两个按钮:● 表示已选中(基于 confirmValue),背景高亮表示光标(仅选择态可见)
35
+ const dot = theme.fg("success", "●");
36
+ const blank = " ";
37
+
38
+ const yesBtn = cursorOnYes
30
39
  ? theme.bg("selectedBg", theme.fg("text", ` [${yesLabel}] `))
31
40
  : ` [${yesLabel}] `;
32
- const noBtn = !selectedYes
41
+ const noBtn = cursorOnNo
33
42
  ? theme.bg("selectedBg", theme.fg("text", ` [${noLabel}] `))
34
43
  : ` [${noLabel}] `;
35
44
 
36
- const arrow = selectedYes
37
- ? theme.fg("accent", ">") + " " + yesBtn + " " + noBtn
38
- : " " + yesBtn + " " + theme.fg("accent", ">") + " " + noBtn;
45
+ const row = selectedYes
46
+ ? dot + " " + yesBtn + " " + blank + " " + noBtn
47
+ : blank + " " + yesBtn + " " + dot + " " + noBtn;
39
48
 
40
- lines.push(truncateToWidth(" " + arrow, width));
49
+ lines.push(truncateToWidth(" " + row, width));
41
50
  return lines;
42
51
  }
package/modules/select.ts CHANGED
@@ -33,15 +33,10 @@ export function renderSelectOptions(
33
33
  const hasCustomText = opt.isCustom && state.customText !== null;
34
34
  const isSelected = state.selectedIndices.includes(i);
35
35
 
36
- // 前缀
37
- let prefix: string;
38
- if (isCursor) {
39
- prefix = theme.fg("accent", "> ");
40
- } else if (isSelected) {
41
- prefix = theme.fg("success", "• ");
42
- } else {
43
- prefix = " ";
44
- }
36
+ // 前缀:两列独立 — 列0: >, 列1: ●
37
+ const col0 = isCursor ? theme.fg("accent", ">") : " ";
38
+ const col1 = isSelected ? theme.fg("success", "●") : " ";
39
+ const prefix = col0 + col1 + " ";
45
40
 
46
41
  // 颜色
47
42
  const color = isCursor ? "accent" : isSelected ? "success" : "text";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lite-questionnaire",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "轻量级交互式问卷工具 — 单选、多选、文本、确认、评分,带条件子问题和声明式校验",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -17,8 +17,12 @@
17
17
  "url": "git+https://github.com/yunwuhai/lite-questionnaire.git"
18
18
  },
19
19
  "pi": {
20
- "extensions": ["./index.ts"],
21
- "skills": ["./skills"],
20
+ "extensions": [
21
+ "./index.ts"
22
+ ],
23
+ "skills": [
24
+ "./skills"
25
+ ],
22
26
  "image": "https://raw.githubusercontent.com/yunwuhai/lite-questionnaire/main/image/logo.png"
23
27
  },
24
28
  "peerDependencies": {
package/render.ts CHANGED
@@ -143,6 +143,9 @@ export function renderHelpBar(
143
143
  theme: { fg: (c: string, t: string) => string },
144
144
  ): string {
145
145
  if (inputMode) {
146
+ if (q?.type === "confirm") {
147
+ return theme.fg("dim", " ← → 切换 · Space 选中 · Enter 确认 · Esc 退出");
148
+ }
146
149
  return theme.fg("dim", " ← → 调整/移动 · Enter 保存 · Esc 退出编辑");
147
150
  }
148
151
 
@@ -162,7 +165,7 @@ export function renderHelpBar(
162
165
  case "text":
163
166
  return theme.fg("dim", " Tab 编辑 · Enter 提交 · Esc 取消" + (isMultiQuestion ? " · ← → 切换问题" : ""));
164
167
  case "confirm":
165
- return theme.fg("dim", " Tab 选择 · Enter 确认 · Esc 取消" + (isMultiQuestion ? " · ← → 切换问题" : ""));
168
+ return theme.fg("dim", " Tab 编辑 · Enter 进入下一栏 · Esc 取消" + (isMultiQuestion ? " · ← → 切换问题" : ""));
166
169
  case "rating":
167
170
  return theme.fg("dim", " Tab 调整 · Enter 确认 · Esc 取消" + (isMultiQuestion ? " · ← → 切换问题" : ""));
168
171
  default: