@springbrand/message-panel 0.2.0-alpha.50 → 0.2.0-alpha.51

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.
@@ -146,6 +146,7 @@ interface AskQuestion {
146
146
  prompt: string;
147
147
  options: string[];
148
148
  allowCustom: boolean;
149
+ required: boolean;
149
150
  responseType: "text" | "single_select" | "multi_select" | "attachment";
150
151
  }
151
152
 
@@ -176,6 +177,7 @@ function questionsOf(input: Record<string, unknown>): AskQuestion[] {
176
177
  : "Choose an option",
177
178
  options,
178
179
  allowCustom: responseType === "text" || question.allowCustom === true,
180
+ required: question.required === true,
179
181
  responseType,
180
182
  };
181
183
  });
@@ -436,19 +438,25 @@ export function AskUserBlock({
436
438
  };
437
439
  // 服务端已经结算 = 这张卡永久不可操作,不管结算成什么。
438
440
  const resolved = outcome.kind !== "pending" || inFlight;
439
- const valid = questions.length > 0 && questions.every(
440
- (question, index) => question.responseType === "attachment"
441
- ? Boolean(
442
- attachmentField &&
443
- attachmentField.attachments.length > 0 &&
444
- !attachmentField.busy &&
445
- !attachmentField.hasFailure
446
- )
447
- : question.responseType === "text"
448
- ? Boolean(answerAt(index).text.trim())
449
- : answerAt(index).selections.length > 0 ||
450
- (question.allowCustom && Boolean(answerAt(index).text.trim())),
451
- );
441
+ const valid = questions.length > 0 && questions.every((question, index) => {
442
+ const answer = answerAt(index);
443
+ const attachmentCount = question.responseType === "attachment"
444
+ ? attachmentField?.attachments.length ?? 0
445
+ : 0;
446
+ if (
447
+ !question.required && attachmentCount === 0 &&
448
+ answer.selections.length === 0 && !answer.text.trim()
449
+ ) return true;
450
+ if (question.responseType === "attachment") {
451
+ return Boolean(
452
+ attachmentCount > 0 && attachmentField &&
453
+ !attachmentField.busy && !attachmentField.hasFailure,
454
+ );
455
+ }
456
+ if (question.responseType === "text") return Boolean(answer.text.trim());
457
+ return answer.selections.length > 0 ||
458
+ (question.allowCustom && Boolean(answer.text.trim()));
459
+ });
452
460
  const buttonLabel = inFlight ? "Submitting…" : "Submit";
453
461
  const footnote = outcome.kind === "closed"
454
462
  ? outcome.reason === "user_replied_freeform"
@@ -525,6 +533,9 @@ export function AskUserBlock({
525
533
  >
526
534
  <p className="m-0 text-[14px] leading-[1.4] font-normal text-kumo-default">
527
535
  {question.prompt}
536
+ {!question.required && (
537
+ <span className="ml-1 text-kumo-inactive">Optional</span>
538
+ )}
528
539
  </p>
529
540
  {question.responseType === "attachment" && (
530
541
  <AskUserAttachmentField
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/message-panel",
3
- "version": "0.2.0-alpha.50",
3
+ "version": "0.2.0-alpha.51",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -705,10 +705,14 @@ function CamelAskUser({
705
705
  const resolvedSubmitted = settledAnswers.length > 0;
706
706
  const valid = questions.length > 0 && questions.every((question, index) => {
707
707
  const responseType = askUserResponseType(question);
708
+ const answer = answerAt(index);
709
+ if (
710
+ answer.selections.length === 0 && !answer.text.trim()
711
+ ) return question.required !== true;
708
712
  if (responseType === "attachment") return false;
709
- if (responseType === "text") return Boolean(answerAt(index).text.trim());
710
- return answerAt(index).selections.length > 0 ||
711
- (question.allowCustom === true && Boolean(answerAt(index).text.trim()));
713
+ if (responseType === "text") return Boolean(answer.text.trim());
714
+ return answer.selections.length > 0 ||
715
+ (question.allowCustom === true && Boolean(answer.text.trim()));
712
716
  });
713
717
 
714
718
  return (
@@ -745,7 +749,12 @@ function CamelAskUser({
745
749
  : [];
746
750
  return (
747
751
  <div className="space-y-2" key={`${prompt}:${questionIndex}`}>
748
- <p className="text-sm text-foreground">{prompt}</p>
752
+ <p className="text-sm text-foreground">
753
+ {prompt}
754
+ {question.required !== true && (
755
+ <span className="ml-1 text-muted-foreground">Optional</span>
756
+ )}
757
+ </p>
749
758
  {attachmentQuestion && settledAttachments.length === 0 && (
750
759
  <p className="text-xs text-muted-foreground">
751
760
  File upload is unavailable in this preview.
@@ -842,9 +851,7 @@ function CamelAskUser({
842
851
  <Button
843
852
  type="button"
844
853
  size="sm"
845
- disabled={resolvedSubmitted || !valid || questions.some((question) =>
846
- askUserResponseType(question) === "attachment"
847
- )}
854
+ disabled={resolvedSubmitted || !valid}
848
855
  onClick={() => {
849
856
  onAnswer({
850
857
  answers: questions.map((_, index) => ({
@@ -837,6 +837,7 @@ export interface AskQuestion {
837
837
  responseType: "text" | "single_select" | "multi_select" | "attachment";
838
838
  options?: string[];
839
839
  allowCustom?: boolean;
840
+ required?: boolean;
840
841
  }
841
842
 
842
843
  function askQuestionResponseType(question: AskQuestion) {
@@ -878,10 +879,14 @@ export function AskUserPart({
878
879
  const valid = questions.length > 0 && questions.every(
879
880
  (question, index) => {
880
881
  const responseType = askQuestionResponseType(question);
882
+ const answer = answerAt(index);
883
+ if (
884
+ answer.selections.length === 0 && !answer.text.trim()
885
+ ) return question.required !== true;
881
886
  if (responseType === "attachment") return false;
882
- if (responseType === "text") return Boolean(answerAt(index).text.trim());
883
- return answerAt(index).selections.length > 0 ||
884
- (question.allowCustom === true && Boolean(answerAt(index).text.trim()));
887
+ if (responseType === "text") return Boolean(answer.text.trim());
888
+ return answer.selections.length > 0 ||
889
+ (question.allowCustom === true && Boolean(answer.text.trim()));
885
890
  },
886
891
  );
887
892
  const toggle = (questionIndex: number, option: string) => {
@@ -933,7 +938,10 @@ export function AskUserPart({
933
938
  key={`${questionIndex}:${question.question}`}
934
939
  disabled={resolvedSubmitted || inFlight || !onSubmit}
935
940
  >
936
- <legend>{question.question}</legend>
941
+ <legend>
942
+ {question.question}
943
+ {question.required !== true && <span> Optional</span>}
944
+ </legend>
937
945
  <div>
938
946
  {choice && (question.options ?? []).map((option) => {
939
947
  const selected = submittedAnswers[questionIndex]