chore(ask): reorganize docs and fix repo checks
This commit is contained in:
+12
-12
@@ -32,12 +32,12 @@ export function cloneResultAnswer(answer: AskResultAnswer): AskResultAnswer {
|
||||
export function toggleSelection(
|
||||
answer: AskStateAnswer,
|
||||
option: AskDisplayOption,
|
||||
index: number,
|
||||
index: number
|
||||
): AskStateAnswer {
|
||||
const next = cloneAnswer(answer);
|
||||
delete next.customText;
|
||||
next.customText = undefined;
|
||||
const selectedIndex = next.selected.findIndex(
|
||||
(selection) => selection.value === option.value,
|
||||
(selection) => selection.value === option.value
|
||||
);
|
||||
|
||||
if (selectedIndex >= 0) {
|
||||
@@ -56,7 +56,7 @@ export function toggleSelection(
|
||||
export function setSingleSelection(
|
||||
answer: AskStateAnswer,
|
||||
option: AskDisplayOption,
|
||||
index: number,
|
||||
index: number
|
||||
): AskStateAnswer {
|
||||
return {
|
||||
...emptyAnswer(),
|
||||
@@ -74,13 +74,13 @@ export function setSingleSelection(
|
||||
|
||||
export function saveCustomText(
|
||||
answer: AskStateAnswer,
|
||||
rawValue: string,
|
||||
rawValue: string
|
||||
): AskStateAnswer {
|
||||
const trimmed = rawValue.trim();
|
||||
const next = cloneAnswer(answer);
|
||||
next.selected = [];
|
||||
if (!trimmed) {
|
||||
delete next.customText;
|
||||
next.customText = undefined;
|
||||
return next;
|
||||
}
|
||||
next.customText = rawValue;
|
||||
@@ -89,21 +89,21 @@ export function saveCustomText(
|
||||
|
||||
export function saveQuestionNote(
|
||||
answer: AskStateAnswer,
|
||||
rawValue: string,
|
||||
rawValue: string
|
||||
): AskStateAnswer {
|
||||
const next = cloneAnswer(answer);
|
||||
if (rawValue.trim()) {
|
||||
next.note = rawValue;
|
||||
return next;
|
||||
}
|
||||
delete next.note;
|
||||
next.note = undefined;
|
||||
return next;
|
||||
}
|
||||
|
||||
export function saveOptionNote(
|
||||
answer: AskStateAnswer,
|
||||
optionValue: string,
|
||||
rawValue: string,
|
||||
rawValue: string
|
||||
): AskStateAnswer {
|
||||
const next = cloneAnswer(answer);
|
||||
const optionNotes = { ...(next.optionNotes ?? {}) };
|
||||
@@ -135,10 +135,10 @@ export function isAnswerAnswered(answer?: AskStateAnswer): boolean {
|
||||
|
||||
export function isOptionSelected(
|
||||
answer: AskStateAnswer | undefined,
|
||||
optionValue: string,
|
||||
optionValue: string
|
||||
): boolean {
|
||||
return !!answer?.selected.some(
|
||||
(selection) => selection.value === optionValue,
|
||||
(selection) => selection.value === optionValue
|
||||
);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ export function serializeAnswer(answer: AskStateAnswer): AskResultAnswer {
|
||||
selection.value,
|
||||
answer.optionNotes?.[selection.value],
|
||||
])
|
||||
.filter((entry): entry is [string, string] => !!entry[1]),
|
||||
.filter((entry): entry is [string, string] => !!entry[1])
|
||||
)
|
||||
: undefined;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { AskParams } from "../types.ts";
|
||||
import { normalizeQuestions } from "./normalize.ts";
|
||||
import { createInitialState as createBaseState } from "./transitions.ts";
|
||||
|
||||
export function createInitialState(params: AskParams) {
|
||||
return createBaseState({
|
||||
title: params.title,
|
||||
questions: normalizeQuestions(params),
|
||||
});
|
||||
}
|
||||
@@ -2,13 +2,13 @@ import type { AskParams, AskQuestion, AskQuestionInput } from "../types.ts";
|
||||
|
||||
export function normalizeQuestions(params: AskParams): AskQuestion[] {
|
||||
return params.questions.map((question, index) =>
|
||||
normalizeQuestion(question, index),
|
||||
normalizeQuestion(question, index)
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeQuestion(
|
||||
question: AskQuestionInput,
|
||||
index: number,
|
||||
index: number
|
||||
): AskQuestion {
|
||||
return {
|
||||
...question,
|
||||
|
||||
+3
-4
@@ -7,10 +7,9 @@ export function toAskResult(state: AskState): AskResult {
|
||||
const answers = Object.fromEntries(
|
||||
Object.entries(state.answers)
|
||||
.map(
|
||||
([questionId, answer]) =>
|
||||
[questionId, serializeAnswer(answer)] as const,
|
||||
([questionId, answer]) => [questionId, serializeAnswer(answer)] as const
|
||||
)
|
||||
.filter(([, answer]) => !isSerializedAnswerEmpty(answer)),
|
||||
.filter(([, answer]) => !isSerializedAnswerEmpty(answer))
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -41,7 +40,7 @@ export function hasAnswerContent(state: AskState, questionId: string): boolean {
|
||||
}
|
||||
|
||||
function isSerializedAnswerEmpty(
|
||||
answer: AskResult["answers"][string],
|
||||
answer: AskResult["answers"][string]
|
||||
): boolean {
|
||||
return (
|
||||
answer.values.length === 0 &&
|
||||
|
||||
+10
-10
@@ -13,7 +13,7 @@ export function getCurrentQuestion(state: AskState): AskQuestion | undefined {
|
||||
|
||||
export function getQuestionById(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): AskQuestion | undefined {
|
||||
return state.questions.find((question) => question.id === questionId);
|
||||
}
|
||||
@@ -23,7 +23,7 @@ export function isSubmitTab(state: AskState): boolean {
|
||||
}
|
||||
|
||||
export function getRenderableOptions(
|
||||
question?: AskQuestion,
|
||||
question?: AskQuestion
|
||||
): AskDisplayOption[] {
|
||||
if (!question) {
|
||||
return [];
|
||||
@@ -43,7 +43,7 @@ export function getRenderableOptions(
|
||||
}
|
||||
|
||||
export function getCurrentOption(
|
||||
state: AskState,
|
||||
state: AskState
|
||||
): AskDisplayOption | undefined {
|
||||
return getRenderableOptions(getCurrentQuestion(state))[
|
||||
state.activeOptionIndex
|
||||
@@ -52,14 +52,14 @@ export function getCurrentOption(
|
||||
|
||||
export function getAnswer(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): AskStateAnswer | undefined {
|
||||
return state.answers[questionId];
|
||||
}
|
||||
|
||||
export function getQuestionNote(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): string | undefined {
|
||||
return getAnswer(state, questionId)?.note;
|
||||
}
|
||||
@@ -67,21 +67,21 @@ export function getQuestionNote(
|
||||
export function getOptionNote(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
optionValue: string,
|
||||
optionValue: string
|
||||
): string | undefined {
|
||||
return getAnswer(state, questionId)?.optionNotes?.[optionValue];
|
||||
}
|
||||
|
||||
export function isQuestionAnswered(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): boolean {
|
||||
return isAnswerAnswered(getAnswer(state, questionId));
|
||||
}
|
||||
|
||||
export function isQuestionNoteOpen(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): boolean {
|
||||
return (
|
||||
state.view.kind === "note" &&
|
||||
@@ -93,7 +93,7 @@ export function isQuestionNoteOpen(
|
||||
export function isOptionNoteOpen(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
optionValue: string,
|
||||
optionValue: string
|
||||
): boolean {
|
||||
return (
|
||||
state.view.kind === "note" &&
|
||||
@@ -104,7 +104,7 @@ export function isOptionNoteOpen(
|
||||
|
||||
export function isInputOpenForQuestion(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): boolean {
|
||||
return state.view.kind === "input" && state.view.questionId === questionId;
|
||||
}
|
||||
|
||||
+18
-18
@@ -58,7 +58,7 @@ export function reduceAskState(state: AskState, action: AskAction): AskState {
|
||||
case "OPEN_OPTION_NOTE":
|
||||
return setView(
|
||||
state,
|
||||
optionNoteView(action.questionId, action.optionValue),
|
||||
optionNoteView(action.questionId, action.optionValue)
|
||||
);
|
||||
case "CONFIRM":
|
||||
return confirmCurrentSelection(state);
|
||||
@@ -97,7 +97,7 @@ export function enterInputMode(state: AskState, questionId: string): AskState {
|
||||
|
||||
export function enterQuestionNoteMode(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
questionId: string
|
||||
): AskState {
|
||||
return reduceAskState(state, { type: "OPEN_QUESTION_NOTE", questionId });
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export function enterQuestionNoteMode(
|
||||
export function enterOptionNoteMode(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
optionValue: string,
|
||||
optionValue: string
|
||||
): AskState {
|
||||
return reduceAskState(state, {
|
||||
type: "OPEN_OPTION_NOTE",
|
||||
@@ -130,13 +130,13 @@ export function toggleCurrentOption(state: AskState): AskState {
|
||||
|
||||
if (question.type === "multi") {
|
||||
return updateAnswer(state, question.id, (answer) =>
|
||||
toggleSelection(answer, option, state.activeOptionIndex),
|
||||
toggleSelection(answer, option, state.activeOptionIndex)
|
||||
);
|
||||
}
|
||||
|
||||
return updateAnswer(state, question.id, (answer) => {
|
||||
const isSelected = answer.selected.some(
|
||||
(selection) => selection.value === option.value,
|
||||
(selection) => selection.value === option.value
|
||||
);
|
||||
if (isSelected) {
|
||||
return {
|
||||
@@ -161,7 +161,7 @@ export function confirmCurrentSelection(state: AskState): AskState {
|
||||
|
||||
const question = getCurrentQuestion(state);
|
||||
const option = getCurrentOption(state);
|
||||
if (!question || !option) {
|
||||
if (!(question && option)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ export function confirmCurrentSelection(state: AskState): AskState {
|
||||
}
|
||||
|
||||
const nextState = updateAnswer(state, question.id, (answer) =>
|
||||
setSingleSelection(answer, option, state.activeOptionIndex),
|
||||
setSingleSelection(answer, option, state.activeOptionIndex)
|
||||
);
|
||||
return advanceToNextTab(nextState);
|
||||
}
|
||||
@@ -205,12 +205,12 @@ export function applyNumberShortcut(state: AskState, digit: number): AskState {
|
||||
|
||||
if (question.type === "multi") {
|
||||
return updateAnswer(selectedState, question.id, (answer) =>
|
||||
toggleSelection(answer, option, index),
|
||||
toggleSelection(answer, option, index)
|
||||
);
|
||||
}
|
||||
|
||||
const nextState = updateAnswer(selectedState, question.id, (answer) =>
|
||||
setSingleSelection(answer, option, index),
|
||||
setSingleSelection(answer, option, index)
|
||||
);
|
||||
return advanceToNextTab(nextState);
|
||||
}
|
||||
@@ -221,7 +221,7 @@ export function saveCustomAnswer(state: AskState, rawValue: string): AskState {
|
||||
|
||||
export function submitCustomAnswer(
|
||||
state: AskState,
|
||||
rawValue: string,
|
||||
rawValue: string
|
||||
): AskState {
|
||||
return saveInputValue(state, rawValue, true);
|
||||
}
|
||||
@@ -244,7 +244,7 @@ export function cancelFlow(state: AskState): AskState {
|
||||
function saveInputValue(
|
||||
state: AskState,
|
||||
rawValue: string,
|
||||
submit: boolean,
|
||||
submit: boolean
|
||||
): AskState {
|
||||
if (state.view.kind !== "input") {
|
||||
return state;
|
||||
@@ -258,9 +258,9 @@ function saveInputValue(
|
||||
const nextState = updateAnswer(
|
||||
exitEditingView(state),
|
||||
question.id,
|
||||
(answer) => saveCustomText(answer, rawValue),
|
||||
(answer) => saveCustomText(answer, rawValue)
|
||||
);
|
||||
if (!submit || !isAnswerAnswered(nextState.answers[question.id])) {
|
||||
if (!(submit && isAnswerAnswered(nextState.answers[question.id]))) {
|
||||
return nextState;
|
||||
}
|
||||
return advanceToNextTab(nextState);
|
||||
@@ -278,7 +278,7 @@ function saveNoteValue(state: AskState, rawValue: string): AskState {
|
||||
(answer) =>
|
||||
optionValue
|
||||
? saveOptionNote(answer, optionValue, rawValue)
|
||||
: saveQuestionNote(answer, rawValue),
|
||||
: saveQuestionNote(answer, rawValue)
|
||||
);
|
||||
return nextState;
|
||||
}
|
||||
@@ -303,7 +303,7 @@ function moveOptionBy(state: AskState, delta: 1 | -1): AskState {
|
||||
activeSubmitActionIndex: clamp(
|
||||
state.activeSubmitActionIndex + delta,
|
||||
0,
|
||||
SUBMIT_ACTION_COUNT - 1,
|
||||
SUBMIT_ACTION_COUNT - 1
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -314,7 +314,7 @@ function moveOptionBy(state: AskState, delta: 1 | -1): AskState {
|
||||
activeOptionIndex: clamp(
|
||||
state.activeOptionIndex + delta,
|
||||
0,
|
||||
Math.max(0, options.length - 1),
|
||||
Math.max(0, options.length - 1)
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -348,8 +348,8 @@ function updateAnswer(
|
||||
state: AskState,
|
||||
questionId: string,
|
||||
mutate: (
|
||||
answer: ReturnType<typeof emptyAnswer>,
|
||||
) => ReturnType<typeof emptyAnswer>,
|
||||
answer: ReturnType<typeof emptyAnswer>
|
||||
) => ReturnType<typeof emptyAnswer>
|
||||
): AskState {
|
||||
const existing = getAnswer(state, questionId) ?? emptyAnswer();
|
||||
const nextAnswer = mutate(existing);
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ export function questionNoteView(questionId: string): ViewState {
|
||||
|
||||
export function optionNoteView(
|
||||
questionId: string,
|
||||
optionValue: string,
|
||||
optionValue: string
|
||||
): ViewState {
|
||||
return { kind: "note", questionId, optionValue };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user