@marktiderman/genesis-forms-studio 0.5.0 → 0.5.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.
- package/dist/{chunk-KUYYXBEN.js → chunk-NQYZ7PHD.js} +2 -2
- package/dist/chunk-NQYZ7PHD.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/rules.d.ts +1 -1
- package/dist/rules.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-KUYYXBEN.js.map +0 -1
|
@@ -696,5 +696,5 @@ function offersSubmitAnother(form) {
|
|
|
696
696
|
}
|
|
697
697
|
|
|
698
698
|
export { FORM_READINESS_LABELS, FORM_READINESS_OPTIONS, NO_FILTERS, RESPONSE_STATUS_LABEL, SAVE_STATE_LABEL, SLUG_PATTERN, STATUS_FILTER_LABEL, answerCell, answerColumns, answersByKey, comparisonFilter, copyTitle, dayLabel, dropOffByQuestion, dropOffSummary, embedSnippet, filterResponses, followUpOf, formAvailability, formCounts, formNavItems, formStatusChip, freeSlug, hasLowRating, hasLowRatingExcept, headlineCards, headlineNumbers, highestRating, isFiltered, isFull, lowRatingAtMost, lowRatingLabel, lowScaleAtMost, lowThisWeek, lowestRating, matchesStatus, needsFollowUp, offersSubmitAnother, parseInstant, plainLabel, prefilledUrl, presetRange, readinessChip, readinessOf, slugFromTitle, summarizeResponses, takesResponses, toCsv, toResponseFilter, validateSlug, valuesByKey };
|
|
699
|
-
//# sourceMappingURL=chunk-
|
|
700
|
-
//# sourceMappingURL=chunk-
|
|
699
|
+
//# sourceMappingURL=chunk-NQYZ7PHD.js.map
|
|
700
|
+
//# sourceMappingURL=chunk-NQYZ7PHD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/answers.ts","../src/summary.ts","../src/headline.ts","../src/dropoff.ts","../src/followups.ts","../src/availability.ts","../src/status.ts","../src/moved-rules.ts","../src/slug.ts","../src/respondent.ts"],"names":["addDays","at","UI_SAVE_STATE_LABEL","uiDayLabel","uiPrefilledUrl","uiEmbedSnippet","uiReadinessOf","uiReadinessChip"],"mappings":";;;;;AAoBA,IAAM,SAAA,uBAAgB,OAAA,EAAwF;AAC9G,SAAS,aAAa,OAAA,EAAuD;AAC3E,EAAA,IAAI,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,OAAO,CAAA;AAC/B,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,GAAA,uBAAU,GAAA,EAAI;AACd,IAAA,KAAA,MAAW,CAAA,IAAK,OAAA,EAAS,IAAI,CAAC,IAAI,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA,EAAG,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,KAAA,EAAO,EAAE,KAAK,CAAA;AACxE,IAAA,SAAA,CAAU,GAAA,CAAI,SAAS,GAAG,CAAA;AAAA,EAC5B;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,UAAA,CAAW,OAAmB,KAAA,EAA+B;AAC3E,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM,OAAO,EAAA;AAClD,EAAA,IAAI,MAAM,IAAA,KAAS,QAAA;AACjB,IAAA,OAAO,UAAU,IAAA,GAAO,KAAA,GAAQ,UAAU,KAAA,GAAQ,IAAA,GAAO,OAAO,KAAK,CAAA;AACvE,EAAA,IAAI,MAAM,IAAA,KAAS,SAAA;AACjB,IAAA,OAAO,UAAU,IAAA,GAAO,QAAA,GAAW,UAAU,KAAA,GAAQ,cAAA,GAAiB,OAAO,KAAK,CAAA;AACpF,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,KAAA,GAAQ,SAAS,CAAC,CAAA,GACjD,KAAA,CAAM,KAAA,CAAM,SAAS,CAAA,GACtB,EAAC;AACL,EAAA,MAAM,MAAA,GAAS,aAAa,OAAO,CAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAY,MAAA,CAAO,IAAI,CAAC,CAAA,IAAK,OAAO,CAAC,CAAA;AAGpD,EAAA,MAAM,aAAa,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAClC,MAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,KAAM,QAAQ,OAAO,CAAA,KAAM,QAAQ,CAAA,GACrD,OAAO,KAAA,KAAU,QAAA;AACrB,EAAA,IAAI,UAAA,EAAY;AAEd,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,KAAA,EAAO,KAAK,CAAA;AAC3C,IAAA,OAAO,OAAA,IAAW,CAAC,OAAA,CAAQ,QAAA,CAAS,iBAAiB,CAAA,GAAI,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAAA,EACzF;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,OAAO,MAAM,GAAA,CAAI,KAAK,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAC3D,EAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAO,KAAA,CAAM,KAAK,CAAA;AACtC,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,SAAA,GAAY,KAAA,GAAQ,OAAO,KAAK,CAAA;AACvF;AAGO,IAAM,UAAA,GAAa,CAAC,KAAA,KACzB,KAAA,CAAM,OAAA,CAAQ,6BAA6B,CAAC,CAAA,EAAG,QAAA,KAAqB,QAAA,IAAY,QAAG;AAa9E,SAAS,aAAA,CACd,WAAA,EACA,IAAA,mBAA4B,IAAI,KAAI,EACpB;AAChB,EAAA,MAAM,UAA0B,EAAC;AACjC,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,IAAA,KAAA,MAAW,KAAA,IAAS,WAAW,MAAA,EAAQ;AACrC,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,IAAK,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AAC1E,MAAA,IAAA,CAAK,GAAA,CAAI,MAAM,GAAG,CAAA;AAClB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAA,EAAK,KAAA,CAAM,GAAA,EAAK,OAAO,UAAA,CAAW,KAAA,CAAM,KAAK,CAAA,EAAG,CAAA;AAAA,IACjE;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAGO,SAAS,YAAA,CACd,YACA,OAAA,EACsB;AACtB,EAAA,MAAM,QAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,KAAA,IAAS,WAAW,MAAA,EAAQ;AACrC,IAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC5B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,EAAE,CAAA;AAC9B,IAAA,IAAI,KAAA,KAAU,QAAW,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA,GAAI,UAAA,CAAW,OAAO,KAAK,CAAA;AAAA,EACrE;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,WAAA,CACd,YACA,OAAA,EACiD;AACjD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAgD;AACnE,EAAA,KAAA,MAAW,KAAA,IAAS,WAAW,MAAA,EAAQ;AACrC,IAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC5B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,EAAE,CAAA;AAC9B,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA;AAAA,EAC1F;AACA,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,KAAA,CAAM,QAA2B,IAAA,EAA4C;AAC3F,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAY;AACzB,IAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,IAAA,MAAM,CAAA,GAAI,OAAO,CAAA,KAAM,QAAA,IAAY,cAAA,CAAe,KAAK,GAAG,CAAA,GAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAC1E,IAAA,OAAO,UAAA,CAAW,IAAA,CAAK,CAAC,CAAA,GAAI,CAAA,CAAA,EAAI,EAAE,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAC,CAAA,CAAA,CAAA,GAAM,CAAA;AAAA,EAC7D,CAAA;AACA,EAAA,OAAO,CAAC,MAAA,EAAQ,GAAG,IAAI,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,CAAI,KAAK,EAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,MAAM,CAAA,GAAI,MAAA;AAC7E;ACzEO,IAAM,mBAAA,GAAoD;AAAA,EAC/D,OAAA,EAAS,kBAAA;AAAA,EACT,SAAA,EAAW,MAAA;AAAA,EACX,OAAA,EAAS,SAAA;AAAA,EACT,WAAA,EAAa;AACf;AAGO,IAAM,qBAAA,GAAwD;AAAA,EACnE,WAAA,EAAa,aAAA;AAAA,EACb,OAAA,EAAS,SAAA;AAAA,EACT,SAAA,EAAW;AACb;AAGO,SAAS,aAAA,CAAc,IAAA,EAAmC,MAAA,GAAuB,SAAA,EAAoB;AAC1G,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,WAAA;AAC9B,EAAA,OAAO,MAAA,KAAW,SAAA,GAAY,MAAA,KAAW,aAAA,GAAgB,MAAA,KAAW,MAAA;AACtE;AAuDA,IAAM,YAAA,uBAAwC,GAAA,CAAI;AAAA,EAChD,eAAA;AAAA,EACA,cAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAC,CAAA;AACD,IAAM,MAAA,GAAS;AAAA,EACb,EAAE,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,KAAA,EAAM;AAAA,EAC9B,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,IAAA;AAC3B,CAAA;AACA,IAAM,OAAA,GAAU;AAAA,EACd,EAAE,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAS;AAAA,EACjC,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,cAAA;AAC3B,CAAA;AAGO,IAAM,YAAA,GAAe,WAAA;AAE5B,IAAM,SAAA,GAAY,CAAC,KAAA,KACjB,KAAA,CAAM,IAAA,KAAS,QAAA,GACX,MAAA,GACA,KAAA,CAAM,IAAA,KAAS,SAAA,GACb,OAAA,GACA,aAAA,CAAc,KAAK,EAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,KAAA,EAAO,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,KAAA,EAAM,CAAE,CAAA;AAEvF,IAAM,SAAA,GAAY,CAAC,KAAA,KAAsB;AACvC,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,KAAA,GAAQ,KAAK,CAAA;AAC/B,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,IAAK,GAAA,IAAO,CAAA,IAAK,GAAA,IAAO,GAAA,GAAM,GAAA,GAAM,CAAA;AAC5F,CAAA;AAGA,IAAM,OAAA,GAAU,CAAC,KAAA,KACf,KAAA,CAAM,SAAS,KAAA,GAAQ,EAAE,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,EAAA,KAAO,KAAA,CAAM,IAAA,KAAS,WAAW,EAAE,GAAA,EAAK,GAAG,GAAA,EAAK,SAAA,CAAU,KAAK,CAAA,EAAE,GAAI,IAAA;AAE7G,IAAM,WAAA,GAAc,CAA6B,KAAA,KAC/C,KAAA,CACG,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,MAAW,EAAE,IAAA,EAAM,KAAA,EAAM,CAAE,CAAA,CACtC,IAAA;AAAA,EAAK,CAAC,CAAA,EAAG,CAAA,KACR,EAAE,IAAA,CAAK,IAAA,GAAO,EAAE,IAAA,CAAK,IAAA,GAAO,IAAI,CAAA,CAAE,IAAA,CAAK,OAAO,CAAA,CAAE,IAAA,CAAK,OAAO,EAAA,GAAK,CAAA,CAAE,QAAQ,CAAA,CAAE;AAC/E,CAAA,CACC,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA;AAMf,SAAS,mBACd,KAAA,EACA,WAAA,EACA,IAAA,mBAA4B,IAAI,KAAI,EACjB;AACnB,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwB;AAC3C,EAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,IAAA,KAAA,MAAW,KAAA,IAAS,WAAW,MAAA,EAAQ;AACrC,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,CAAC,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,IACnF;AAAA,EACF;AACA,EAAA,MAAM,WAAW,WAAA,CAAY,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,IAAA,MAAU;AAAA,IACjD,IAAA;AAAA,IACA,MAAA,EAAQ,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO,CAAA;AAAA,IACjD,KAAA,EAAO,YAAA,CAAa,IAAA,CAAK,UAAA,EAAY,KAAK,OAAO;AAAA,GACnD,CAAE,CAAA;AAEF,EAAA,OAAO,cAAc,WAAA,EAAa,IAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,MAAA,KAA8B;AAC7E,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA;AACnC,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,IAAA,MAAM,EAAE,GAAA,EAAK,KAAA,EAAM,GAAI,MAAA;AAEvB,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,QAAA,IAAY,KAAA,CAAM,SAAS,KAAA,EAAO;AACnD,MAAA,MAAM,GAAA,GAAM,MAAM,IAAA,KAAS,KAAA;AAG3B,MAAA,MAAM,GAAA,GAAM,MAAM,CAAA,GAAI,CAAA;AACtB,MAAA,MAAM,GAAA,GAAM,GAAA,GAAM,EAAA,GAAK,SAAA,CAAU,KAAK,CAAA;AACtC,MAAA,MAAM,MAAA,GAAS,IAAI,KAAA,CAAc,GAAA,GAAM,MAAM,CAAC,CAAA,CAAE,KAAK,CAAC,CAAA;AACtD,MAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,MAAA,IAAI,GAAA,GAAM,CAAA;AACV,MAAA,IAAI,SAAA,GAAY,CAAA;AAChB,MAAA,IAAI,UAAA,GAAa,CAAA;AACjB,MAAA,IAAI,QAAA,GAAW,CAAA;AACf,MAAA,IAAI,QAAA,GAAW,CAAA;AACf,MAAA,KAAA,MAAW,EAAE,MAAA,EAAO,IAAK,QAAA,EAAU;AACjC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC7B,QAAA,IAAI,CAAC,MAAA,EAAQ;AACb,QAAA,MAAM,IAAI,MAAA,CAAO,KAAA;AACjB,QAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAA;AAChC,QAAA,IAAI,CAAC,GAAA,IAAO,OAAO,CAAA,KAAM,YAAY,CAAC,MAAA,CAAO,SAAA,CAAU,CAAC,KAAK,CAAA,GAAI,GAAA,CAAI,GAAA,IAAO,CAAA,GAAI,IAAI,GAAA,EAAK;AACvF,UAAA,QAAA,EAAA;AACA,UAAA;AAAA,QACF;AACA,QAAA,IAAI,CAAA,GAAI,CAAA;AACR,QAAA,IAAI,GAAA,CAAI,GAAA,KAAQ,GAAA,IAAO,GAAA,CAAI,QAAQ,GAAA,EAAK;AAEtC,UAAA,CAAA,GAAI,GAAA,CAAI,GAAA,KAAQ,GAAA,CAAI,GAAA,GAAM,GAAA,GAAM,GAAA,GAAA,CAAQ,CAAA,GAAI,GAAA,CAAI,GAAA,KAAQ,GAAA,GAAM,GAAA,CAAA,IAAS,GAAA,CAAI,MAAM,GAAA,CAAI,GAAA,CAAA;AACrF,UAAA,QAAA,EAAA;AAAA,QACF;AACA,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAC1B,QAAA,MAAA,CAAO,KAAA,GAAQ,GAAG,CAAA,IAAM,CAAA;AACxB,QAAA,KAAA,EAAA;AACA,QAAA,GAAA,IAAO,CAAA;AACP,QAAA,IAAI,SAAS,CAAA,EAAG,SAAA,EAAA;AAAA,aAAA,IACP,SAAS,CAAA,EAAG,UAAA,EAAA;AAAA,MACvB;AACA,MAAA,OAAO;AAAA,QACL;AAAA,UACE,IAAA,EAAM,OAAA;AAAA,UACN,GAAA;AAAA,UACA,KAAA;AAAA,UACA,MAAM,KAAA,CAAM,IAAA;AAAA,UACZ,WAAW,KAAA,CAAM,IAAA;AAAA,UACjB,KAAA;AAAA,UACA,GAAA;AAAA,UACA,GAAA;AAAA,UACA,OAAA,EAAS,KAAA,GAAQ,GAAA,GAAM,KAAA,GAAQ,IAAA;AAAA,UAC/B,OAAA,EAAS,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,MAAO,EAAE,KAAA,EAAO,GAAA,GAAM,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE,CAAE,CAAA;AAAA,UAC5D,QAAA;AAAA,UACA,QAAA;AAAA,UACA,GAAA,EACE,OAAO,KAAA,GACH;AAAA,YACE,SAAA;AAAA,YACA,QAAA,EAAU,QAAQ,SAAA,GAAY,UAAA;AAAA,YAC9B,UAAA;AAAA,YACA,OAAO,IAAA,CAAK,KAAA,CAAA,CAAQ,SAAA,GAAY,UAAA,IAAc,QAAS,GAAG;AAAA,WAC5D,GACA;AAAA;AACR,OACF;AAAA,IACF;AAEA,IAAA,IAAI,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,EAAG;AAChC,MAAA,MAAM,OAAA,GAAU,SAAA,CAAU,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE,CAAE,CAAA;AAEhE,MAAA,MAAM,OAAA,uBAAc,GAAA,EAAsC;AAC1D,MAAA,KAAA,MAAW,CAAA,IAAK,OAAA,EAAS,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA,EAAG,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,OAAO,CAAC,CAAA;AAC1E,MAAA,MAAM,GAAA,GAAM,CAAC,MAAA,KAAqC;AAChD,QAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AACnB,QAAA,OAAA,CAAQ,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,MAAM,CAAA;AAChC,QAAA,OAAO,MAAA;AAAA,MACT,CAAA;AACA,MAAA,MAAM,UAAA,uBAAiB,GAAA,EAAiD;AACxE,MAAA,MAAM,SAAA,GAAY,CAAC,IAAA,EAAkB,KAAA,KAAkB;AACrD,QAAA,IAAI,GAAA,GAAM,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA;AAC7B,QAAA,IAAI,CAAC,GAAA,EAAK;AACR,UAAA,GAAA,uBAAU,GAAA,EAAI;AACd,UAAA,KAAA,MAAW,CAAA,IAAK,SAAA,CAAU,IAAI,CAAA,MAAO,CAAC,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,KAAK,CAAA,EAAG,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,OAAO,CAAC,CAAA;AAC1E,UAAA,UAAA,CAAW,GAAA,CAAI,MAAM,GAAG,CAAA;AAAA,QAC1B;AACA,QAAA,OAAO,GAAA,CAAI,IAAI,KAAK,CAAA;AAAA,MACtB,CAAA;AACA,MAAA,MAAM,IAAA,GAAO,CAAC,KAAA,EAAe,IAAA,KAAqB;AAChD,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AAC/B,QAAA,IAAI,OAAO,OAAO,KAAA;AAGlB,QAAA,IAAI,YAAA,CAAa,IAAA,EAAM,KAAK,CAAA,EAAG;AAC7B,UAAA,OACE,QAAQ,GAAA,CAAI,YAAY,KACxB,GAAA,CAAI,EAAE,OAAO,YAAA,EAAc,KAAA,EAAA,CAAQ,WAAA,CAAY,KAAK,KAAK,WAAA,CAAY,IAAI,GAAI,KAAA,EAAO,KAAA,EAAO,GAAG,CAAA;AAAA,QAElG;AAEA,QAAA,OAAO,GAAA,CAAI,EAAE,KAAA,EAAO,KAAA,EAAO,SAAA,CAAU,IAAA,EAAM,KAAK,CAAA,EAAG,KAAA,IAAS,KAAA,EAAO,KAAA,EAAO,CAAA,EAAG,CAAA;AAAA,MAC/E,CAAA;AACA,MAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,MAAA,KAAA,MAAW,EAAE,MAAA,EAAO,IAAK,QAAA,EAAU;AACjC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC7B,QAAA,IAAI,CAAC,MAAA,EAAQ;AACb,QAAA,MAAM,MAAA,GAAA,CAAU,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAA,GAAI,MAAA,CAAO,KAAA,GAAQ,CAAC,MAAA,CAAO,KAAK,CAAA,EAAG,MAAA;AAAA,UAC3E,CAAC,CAAA,KAA6B,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,CAAA,KAAM;AAAA,SACtE;AACA,QAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AACpB,QAAA,KAAA,EAAA;AACA,QAAA,KAAA,MAAW,CAAA,IAAK,IAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,MAAM,CAAC,CAAA,EAAG,IAAA,CAAK,CAAA,EAAG,MAAA,CAAO,KAAK,CAAA,CAAE,KAAA,EAAA;AAAA,MACrE;AACA,MAAA,OAAO;AAAA,QACL;AAAA,UACE,IAAA,EAAM,QAAA;AAAA,UACN,GAAA;AAAA,UACA,KAAA;AAAA,UACA,WAAW,KAAA,CAAM,IAAA;AAAA,UACjB,KAAA;AAAA,UACA,QAAA,EAAU,MAAM,IAAA,KAAS,cAAA;AAAA,UACzB,OAAA,EAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,CAAA,EAAG,OAAA,EAAS,QAAS,CAAA,CAAE,KAAA,GAAQ,KAAA,GAAS,GAAA,GAAM,GAAE,CAAE;AAAA;AACtF,OACF;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,QAAA,CAAS,OAAA,CAAQ,CAAC,EAAE,IAAA,EAAM,OAAM,KAAM;AACpD,MAAA,MAAM,OAAO,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,IAAK,EAAE,EAAE,IAAA,EAAK;AAC3C,MAAA,OAAO,IAAA,GAAO,CAAC,EAAE,EAAA,EAAI,IAAA,CAAK,EAAA,EAAI,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,CAAA,GAAI,EAAC;AAAA,IAC5D,CAAC,CAAA;AACD,IAAA,OAAO,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,GAAA,EAAK,KAAA,EAAO,SAAA,EAAW,KAAA,CAAM,IAAA,EAAM,KAAA,EAAO,OAAA,CAAQ,MAAA,EAAQ,SAAS,CAAA;AAAA,EAC7F,CAAC,CAAA;AACH;AAGO,SAAS,cAAc,WAAA,EAAuD;AACnF,EAAA,IAAI,GAAA,GAAqB,IAAA;AACzB,EAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,IAAA,KAAA,MAAW,KAAA,IAAS,WAAW,MAAA,EAAQ;AACrC,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,KAAA,CAAM,IAAA,KAAS,QAAA;AAC3C,QAAA,GAAA,GAAM,KAAK,GAAA,CAAI,GAAA,IAAO,CAAA,EAAG,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,IAC7C;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,aAAa,IAAA,EAAkC;AAC7D,EAAA,IAAI,MAAA,GAAwB,IAAA;AAC5B,EAAA,KAAA,MAAW,EAAE,KAAA,EAAO,KAAA,EAAM,IAAK,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,OAAO,CAAA,CAAE,MAAA,EAAO,EAAG;AAClF,IAAA,IAAI,KAAA,CAAM,SAAS,QAAA,IAAY,OAAO,UAAU,QAAA,KAAa,MAAA,KAAW,QAAQ,KAAA,GAAQ,MAAA,CAAA;AACtF,MAAA,MAAA,GAAS,KAAA;AAAA,EACb;AACA,EAAA,OAAO,MAAA;AACT;AAGA,IAAM,SAAA,GAAY,GAAA;AAElB,IAAM,OAAA,GAAU,CAAA;AAMT,SAAS,gBAAgB,KAAA,EAAkC;AAChE,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,KAAA,EAAO,OAAO,OAAA;AACjC,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACpC,EAAA,OAAO,cAAA,CAAe,QAAA,EAAU,SAAA,CAAU,KAAK,CAAC,CAAA;AAClD;AAGO,SAAS,cAAA,CAAe,MAAwB,GAAA,EAAqB;AAC1E,EAAA,OAAO,IAAA,KAAS,KAAA,GAAQ,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,SAAS,CAAC,CAAA;AAC3E;AAGO,SAAS,aAAa,IAAA,EAA4B;AACvD,EAAA,OAAO,kBAAA,CAAmB,IAAA,kBAAM,IAAI,GAAA,EAAK,CAAA;AAC3C;AAGO,SAAS,kBAAA,CAAmB,MAAmB,IAAA,EAAoC;AACxF,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,EAAE,KAAA,EAAO,KAAA,EAAO,CAAA,IAAK,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,OAAO,CAAA,EAAG;AAChF,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,EAAG;AACnB,IAAA,MAAM,MAAA,GAAS,gBAAgB,KAAK,CAAA;AACpC,IAAA,IAAI,WAAW,IAAA,IAAQ,OAAO,UAAU,QAAA,IAAY,KAAA,IAAS,QAAQ,OAAO,IAAA;AAAA,EAC9E;AACA,EAAA,OAAO,KAAA;AACT;AAOO,SAAS,eAAe,WAAA,EAAuD;AACpF,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAY;AAC/B,EAAA,IAAI,GAAA,GAAM,KAAA;AACV,EAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,IAAA,KAAA,MAAW,KAAA,IAAS,WAAW,MAAA,EAAQ;AACrC,MAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC5B,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,KAAA,EAAO,GAAA,GAAM,IAAA;AAAA,WAAA,IACvB,MAAM,IAAA,KAAS,QAAA,SAAiB,GAAA,CAAI,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,IAC/D;AAAA,EACF;AACA,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,IAAA,IAAQ,GAAA,GAAM,IAAI,CAAA,CAAA,GAAK,CAAA;AAC9C,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,MAAM,EACrB,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,CACpB,GAAA,CAAI,CAAC,GAAA,KAAQ;AACZ,IAAA,MAAM,MAAA,GAAS,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,GAAA,GAAM,SAAS,CAAC,CAAA;AACtD,IAAA,OAAO,UAAU,CAAA,EAAG,MAAM,oBAAoB,GAAG,CAAA,CAAA,GAAK,GAAG,MAAM,CAAA,SAAA,CAAA;AAAA,EACjE,CAAC,CAAA;AACH,EAAA,IAAI,GAAA,QAAW,IAAA,CAAK,OAAA,GAAU,UAAK,OAAO,CAAA,OAAA,CAAA,GAAY,CAAA,OAAA,EAAK,OAAO,CAAA,CAAE,CAAA;AACpE,EAAA,OAAO,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA;AAC3C;AAiBO,SAAS,WAAW,MAAA,EAAiC;AAC1D,EAAA,OAAO,OAAA;AAAA,IACL,MAAA,CAAO,IAAA,IACP,MAAA,CAAO,EAAA,IACP,MAAA,CAAO,YAAA,IAAgB,IAAA,IACvB,MAAA,CAAO,GAAA,IACN,MAAA,CAAO,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,SAAA,IACpC,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,KAAA,IAAS,EAAE,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,IAAK,IAAA,IAAQ,CAAA,KAAM,EAAE;AAAA,GACrE;AACF;AAGO,SAAS,eAAA,CACd,OACA,MAAA,EACK;AACL,EAAA,MAAM,QAAQ,MAAA,CAAO,OAAA,CAAQ,OAAO,KAAA,IAAS,EAAE,CAAA,CAAE,MAAA;AAAA,IAC/C,CAAC,MAA6B,CAAA,CAAE,CAAC,KAAK,IAAA,IAAQ,CAAA,CAAE,CAAC,CAAA,KAAM;AAAA,GACzD;AACA,EAAA,OAAO,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAS;AAC5B,IAAA,IAAI,CAAC,aAAA,CAAc,IAAA,EAAM,MAAA,CAAO,MAAM,GAAG,OAAO,KAAA;AAChD,IAAA,IAAI,OAAO,IAAA,IAAQ,IAAA,CAAK,IAAA,GAAO,MAAA,CAAO,MAAM,OAAO,KAAA;AACnD,IAAA,IAAI,OAAO,EAAA,IAAM,IAAA,CAAK,IAAA,GAAO,MAAA,CAAO,IAAI,OAAO,KAAA;AAC/C,IAAA,IAAI,MAAM,IAAA,CAAK,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM,MAAA,CAAO,IAAA,CAAK,KAAA,GAAQ,GAAG,CAAA,IAAK,EAAE,CAAA,KAAM,KAAK,GAAG,OAAO,KAAA;AACpF,IAAA,IAAI,MAAA,CAAO,gBAAgB,IAAA,EAAM;AAC/B,MAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,MAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,GAAS,MAAA,CAAO,cAAc,OAAO,KAAA;AAAA,IAC9D;AACA,IAAA,IAAI,OAAO,GAAA,IAAO,CAAC,YAAA,CAAa,IAAI,GAAG,OAAO,KAAA;AAC9C,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACH;AAIA,IAAM,OAAA,GAAU,CAAC,GAAA,EAAa,CAAA,KAAc;AAC1C,EAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,GAAG,GAAG,CAAA,UAAA,CAAY,IAAI,CAAA,GAAI,KAAA;AAC/C,EAAA,OAAO,IAAI,KAAK,CAAC,CAAA,CAAE,aAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAC9C,CAAA;AAMO,SAAS,WAAA,CACd,QACA,KAAA,EAC4C;AAC5C,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,KAAA;AACH,MAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,EAAA,EAAI,IAAA,EAAK;AAAA,IAChC,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,EAAA,EAAI,KAAA,EAAM;AAAA,IAClC,KAAK,MAAA,EAAQ;AACX,MAAA,MAAM,2BAAU,IAAI,IAAA,CAAK,GAAG,KAAK,CAAA,UAAA,CAAY,GAAE,SAAA,EAAU;AACzD,MAAA,OAAO,EAAE,IAAA,EAAM,OAAA,CAAQ,KAAA,EAAO,EAAA,CAAG,UAAU,CAAA,IAAK,CAAA,CAAE,CAAA,EAAG,EAAA,EAAI,KAAA,EAAM;AAAA,IACjE;AAAA,IACA,KAAK,IAAA;AACH,MAAA,OAAO,EAAE,IAAA,EAAM,OAAA,CAAQ,OAAO,EAAE,CAAA,EAAG,IAAI,KAAA,EAAM;AAAA,IAC/C,KAAK,KAAA;AACH,MAAA,OAAO,EAAE,IAAA,EAAM,OAAA,CAAQ,OAAO,GAAG,CAAA,EAAG,IAAI,KAAA,EAAM;AAAA,IAChD,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,KAAA,CAAM,KAAA,CAAM,GAAG,CAAC,CAAC,CAAA,GAAA,CAAA,EAAO,EAAA,EAAI,KAAA,EAAM;AAAA;AAE1D;AAmBO,IAAM,UAAA,GAA2B;AAAA,EACtC,IAAA,EAAM,KAAA;AAAA,EACN,IAAA,EAAM,EAAA;AAAA,EACN,EAAA,EAAI,EAAA;AAAA,EACJ,OAAO,EAAC;AAAA,EACR,YAAA,EAAc,IAAA;AAAA,EACd,GAAA,EAAK;AACP;AAGO,SAAS,gBAAA,CAAiB,OAAqB,KAAA,EAA+B;AACnF,EAAA,MAAM,QACJ,KAAA,CAAM,IAAA,KAAS,QAAA,GACX,EAAE,MAAM,KAAA,CAAM,IAAA,IAAQ,IAAA,EAAM,EAAA,EAAI,MAAM,EAAA,IAAM,IAAA,KAC5C,WAAA,CAAY,KAAA,CAAM,MAAM,KAAK,CAAA;AACnC,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,KAAK,KAAA,CAAM,GAAA;AAAA,IACX,GAAI,MAAM,MAAA,GAAS,EAAE,QAAQ,KAAA,CAAM,MAAA,KAAW;AAAC,GACjD;AACF;AAMO,IAAM,WAAA,GAAc,CAAC,KAAA,MAAuC;AAAA,EACjE,GAAG,KAAA;AAAA,EACH,IAAA,EAAM,MAAA;AAAA,EACN,GAAA,EAAK;AACP,CAAA;;;ACneO,SAAS,eAAA,CACd,KAAA,EACA,WAAA,EACA,OAAA,GAAoF,EAAC,EAC3E;AACV,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,IAAA;AACrC,EAAA,MAAM,SAAA,GAAY,kBAAA,CAAmB,KAAA,EAAO,WAAA,EAAa,QAAQ,IAAI,CAAA;AACrE,EAAA,MAAM,OAAA,GAAU,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,CAAA,CAAE,MAAA;AAC5D,EAAA,MAAM,SAAS,QAAA,GAAW,kBAAA,CAAmB,UAAU,WAAA,EAAa,OAAA,CAAQ,IAAI,CAAA,GAAI,IAAA;AAEpF,EAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,OAAA,IAAW,CAAA,CAAE,IAAA,KAAS,QAAQ,CAAA;AAC7E,EAAA,IAAI,MAAA,GAA6B,IAAA;AACjC,EAAA,IAAI,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,OAAA,EAAS;AACnC,IAAA,MAAM,GAAA,GAAM,MAAA,EAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,OAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,KAAA,CAAM,GAAG,CAAA;AACzE,IAAA,MAAM,kBAAkB,GAAA,IAAO,GAAA,CAAI,IAAA,KAAS,OAAA,GAAU,IAAI,OAAA,GAAU,IAAA;AACpE,IAAA,MAAA,GAAS;AAAA,MACP,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,SAAS,KAAA,CAAM,OAAA;AAAA,MACf,eAAA;AAAA,MACA,MAAA,EACE,KAAA,CAAM,OAAA,KAAY,IAAA,IAAQ,eAAA,KAAoB,IAAA,GAC1C,IAAA,CAAK,KAAA,CAAA,CAAO,KAAA,CAAM,OAAA,GAAU,eAAA,IAAmB,EAAE,IAAI,EAAA,GACrD;AAAA,KACR;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,OAAO,CAAA;AACvD,EAAA,MAAM,MAAA,GACJ,UAAU,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,YAAY,CAAA,CAAE,SAAA,KAAc,SAAS,CAAA,IACtE,SAAA,CAAU,KAAK,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,QAAA,IAAY,CAAA,CAAE,SAAA,KAAc,QAAQ,CAAA;AACvE,EAAA,IAAI,IAAA,GAAyB,IAAA;AAC7B,EAAA,IAAI,MAAA,IAAU,MAAA,CAAO,IAAA,KAAS,QAAA,EAAU;AACtC,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,KAAU,MAAM,CAAA,EAAG,KAAA,IAAS,CAAA;AACrE,IAAA,IAAA,GAAO;AAAA,MACL,KAAK,MAAA,CAAO,GAAA;AAAA,MACZ,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,MAAM,MAAA,CAAO,SAAA;AAAA,MACb,GAAA;AAAA,MACA,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,OAAA,EAAS,OAAO,KAAA,GAAQ,IAAA,CAAK,MAAO,GAAA,GAAM,MAAA,CAAO,KAAA,GAAS,GAAG,CAAA,GAAI;AAAA,KACnE;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,SAAA,EAAW;AAAA,MACT,OAAO,KAAA,CAAM,MAAA;AAAA,MACb,QAAA,EAAU,QAAA,GAAW,QAAA,CAAS,MAAA,GAAS,IAAA;AAAA,MACvC,MAAA,EAAQ,QAAA,GAAW,KAAA,CAAM,MAAA,GAAS,SAAS,MAAA,GAAS,IAAA;AAAA,MACpD,GAAI,OAAA,GAAU,EAAE,OAAA,KAAY;AAAC,KAC/B;AAAA,IACA,MAAA;AAAA;AAAA,IAEA,KAAK,MAAA,GAAS,EAAE,OAAO,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,kBAAA,CAAmB,CAAA,EAAG,OAAA,CAAQ,wBAAQ,IAAI,GAAA,EAAK,CAAC,CAAA,CAAE,QAAO,GAAI,IAAA;AAAA,IACxG;AAAA,GACF;AACF;AAEA,IAAMA,WAAU,CAAC,GAAA,EAAa,MAC5B,IAAI,IAAA,CAAK,KAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,UAAA,CAAY,CAAA,GAAI,IAAI,KAAU,CAAA,CAAE,aAAY,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AACrF,IAAM,cAAc,CAAC,IAAA,EAAc,OACjC,IAAA,CAAK,KAAA,CAAA,CAAO,KAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,UAAA,CAAY,IAAI,IAAA,CAAK,KAAA,CAAM,GAAG,IAAI,CAAA,UAAA,CAAY,KAAK,KAAU,CAAA;AASpF,SAAS,gBAAA,CACd,OACA,KAAA,EACkD;AAClD,EAAA,MAAM,QACJ,KAAA,CAAM,IAAA,KAAS,QAAA,GACX,EAAE,MAAM,KAAA,CAAM,IAAA,IAAQ,IAAA,EAAM,EAAA,EAAI,MAAM,EAAA,IAAM,IAAA,KAC5C,WAAA,CAAY,KAAA,CAAM,MAAM,KAAK,CAAA;AACnC,EAAA,IAAI,CAAC,KAAA,CAAM,IAAA,IAAQ,CAAC,KAAA,CAAM,MAAM,KAAA,CAAM,EAAA,GAAK,KAAA,CAAM,IAAA,EAAM,OAAO,IAAA;AAC9D,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,EAAA;AACJ,EAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,IAAA,MAAM,QAAQ,CAAA,EAAG,KAAA,CAAM,KAAK,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,GAAA,CAAA;AACvC,IAAA,MAAM,SAAA,GAAYA,QAAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACnC,IAAA,IAAA,GAAO,CAAA,EAAG,SAAA,CAAU,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,GAAA,CAAA;AAC/B,IAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,KAAA,CAAM,GAAG,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,GAAG,MAAA,CAAO,SAAA,CAAU,MAAM,CAAA,EAAG,EAAE,CAAC,CAAC,CAAA;AAClF,IAAA,EAAA,GAAK,CAAA,EAAG,SAAA,CAAU,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,GAAG,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAAA,EAC/D,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,MAAA,EAAQ;AAEhC,IAAA,IAAA,GAAOA,QAAAA,CAAQ,KAAA,CAAM,IAAA,EAAM,EAAE,CAAA;AAC7B,IAAA,EAAA,GAAKA,QAAAA,CAAQ,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAAA,EAC3B,CAAA,MAAO;AACL,IAAA,MAAM,SAAS,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,KAAA,CAAM,EAAE,CAAA,GAAI,CAAA;AACnD,IAAA,EAAA,GAAKA,QAAAA,CAAQ,KAAA,CAAM,IAAA,EAAM,EAAE,CAAA;AAC3B,IAAA,IAAA,GAAOA,QAAAA,CAAQ,KAAA,CAAM,IAAA,EAAM,CAAC,MAAM,CAAA;AAAA,EACpC;AACA,EAAA,MAAM,KAAA,GACJ,MAAM,IAAA,KAAS,OAAA,GACX,cACA,KAAA,CAAM,IAAA,KAAS,SACb,WAAA,GACA,KAAA,CAAM,SAAS,OAAA,GACb,YAAA,GACA,MAAM,IAAA,KAAS,IAAA,GACb,sBACA,KAAA,CAAM,IAAA,KAAS,QACb,oBAAA,GACA,iBAAA;AACd,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,IAAA;AAAA,MACA,EAAA;AAAA,MACA,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,cAAc,KAAA,CAAM,YAAA;AAAA,MACpB,KAAK,KAAA,CAAM,GAAA;AAAA,MACX,GAAI,MAAM,MAAA,GAAS,EAAE,QAAQ,KAAA,CAAM,MAAA,KAAW;AAAC,KACjD;AAAA,IACA;AAAA,GACF;AACF;AAEA,IAAM,MAAA,GAAS,CAAC,CAAA,EAAW,MAAA,GAAS,CAAA,KAAM;AACxC,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,CAAE,QAAQ,MAAM,CAAA;AACpC,EAAA,OAAO,CAAA,GAAI,IAAI,CAAA,CAAA,EAAI,CAAC,KAAK,CAAA,GAAI,CAAA,GAAI,CAAA,MAAA,EAAI,CAAC,CAAA,CAAA,GAAK,CAAA;AAC7C,CAAA;AAOO,SAAS,aAAA,CACd,QAAA,EACA,OAAA,GAII,EAAC,EACa;AAClB,EAAA,MAAM,QAA0B,EAAC;AACjC,EAAA,MAAM,EAAE,SAAA,EAAW,MAAA,EAAQ,GAAA,EAAK,MAAK,GAAI,QAAA;AAEzC,EAAA,MAAM,UAAU,SAAA,CAAU,OAAA,GAAU,CAAA,EAAG,SAAA,CAAU,OAAO,CAAA,QAAA,CAAA,GAAa,IAAA;AACrE,EAAA,KAAA,CAAM,IAAA,CAAK;AAAA,IACT,GAAA,EAAK,WAAA;AAAA,IACL,KAAA,EAAO,WAAA;AAAA,IACP,OAAO,SAAA,CAAU,KAAA;AAAA,IACjB,GAAI,SAAA,CAAU,MAAA,KAAW,IAAA,IAAQ,QAAQ,MAAA,GACrC;AAAA,MACE,MAAA,EAAA,CACG,UAAU,MAAA,KAAW,CAAA,GAAI,WAAW,OAAA,CAAQ,MAAM,KAAK,CAAA,EAAG,MAAA,CAAO,UAAU,MAAM,CAAC,OAAO,OAAA,CAAQ,MAAM,OACvG,OAAA,GAAU,CAAA,MAAA,EAAM,OAAO,CAAA,CAAA,GAAK,EAAA,CAAA;AAAA,MAC/B,IAAA,EAAM,UAAU,MAAA,GAAS,CAAA,GAAK,aAAuB,SAAA,CAAU,MAAA,GAAS,IAAK,UAAA,GAAwB;AAAA,KACvG,GACA,UACE,EAAE,MAAA,EAAQ,aAAa,OAAO,CAAA,CAAA,KAC9B;AAAC,GACR,CAAA;AACD,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA,EAAK,QAAA;AAAA,MACL,KAAA,EAAO,gBAAA;AAAA,MACP,KAAA,EAAO,MAAA,CAAO,OAAA,KAAY,IAAA,GAAO,QAAA,GAAM,CAAA,EAAG,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,EAAM,OAAO,GAAG,CAAA,CAAA;AAAA,MACnF,GAAI,MAAA,KAAW,IAAA,IAAQ,OAAA,CAAQ,MAAA,GAC3B;AAAA,QACE,QAAQ,MAAA,KAAW,CAAA,GAAI,WAAW,OAAA,CAAQ,MAAM,KAAK,CAAA,EAAG,MAAA,GAAS,IAAI,IAAA,GAAO,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,QACjH,MAAM,MAAA,GAAS,CAAA,GAAK,UAAA,GAAuB,MAAA,GAAS,IAAK,SAAA,GAAuB;AAAA,OAClF,GACA,OAAO,OAAA,KAAY,IAAA,GACjB,EAAE,MAAA,EAAQ,gBAAA,KACV;AAAC,KACR,CAAA;AAAA,EACH;AACA,EAAA,IAAI,GAAA,EAAK;AACP,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,OAAA,IAAW,GAAA,CAAI,KAAA;AACpC,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA,EAAK,KAAA;AAAA,MACL,KAAA,EAAO,aAAA;AAAA,MACP,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,GAAI,IAAA,GACA,EAAE,QAAQ,IAAA,KAAS,CAAA,GAAI,sBAAsB,CAAA,EAAG,IAAI,CAAA,iBAAA,CAAA,EAAqB,IAAA,EAAM,YAAoB,GACnG,EAAE,QAAQ,GAAA,CAAI,KAAA,GAAQ,oBAAoB,MAAA;AAAO,KACtD,CAAA;AAAA,EACH;AACA,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA,EAAK,MAAA;AAAA,MACL,OAAO,IAAA,CAAK,KAAA,KAAU,IAAA,CAAK,IAAA,KAAS,YAAY,QAAA,GAAW,KAAA,CAAA;AAAA,MAC3D,OAAO,IAAA,CAAK,OAAA,KAAY,OAAO,QAAA,GAAM,CAAA,EAAG,KAAK,OAAO,CAAA,CAAA,CAAA;AAAA,MACpD,MAAA,EAAQ,IAAA,CAAK,KAAA,GACT,CAAA,EAAG,KAAK,GAAG,CAAA,IAAA,EAAO,IAAA,CAAK,KAAK,IAAI,IAAA,CAAK,IAAA,KAAS,SAAA,GAAY,QAAA,GAAW,UAAU,CAAA,CAAA,GAC/E;AAAA,KACL,CAAA;AAAA,EACH;AACA,EAAA,OAAO,KAAA;AACT;AC7NA,SAAS,WAAW,IAAA,EAA6B;AAC/C,EAAA,MAAM,EAAE,YAAW,GAAI,IAAA;AACvB,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAwB;AAC3C,EAAA,KAAA,MAAW,KAAA,IAAS,UAAA,CAAW,MAAA,EAAQ,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,EAAS,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,EAAA,EAAI,KAAK,CAAA;AAC7F,EAAA,MAAM,MAAA,GAA2C,EAAE,GAAG,IAAA,CAAK,OAAA,EAAQ;AACnE,EAAA,IAAI,KAAK,YAAA,EAAc;AACrB,IAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,MAAA,EAAO,EAAG;AACnC,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,KAAK,IAAA,CAAK,YAAA,EAAc,KAAA,CAAM,GAAG,CAAA,GAC1E,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,GAC3B,MAAA;AAEJ,MAAA,IAAI,IAAA,IAAQ,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,EAAE,KAAK,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,GAAI,IAAA;AAAA,IACnE;AAAA,EACF;AACA,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,WAAA,CAAY,UAAA,EAAY,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,EAAC,EAAG,QAAQ,CAAA;AACtF,EAAA,OAAO,KAAK,MAAA,CAAO,CAAC,OAAO,MAAA,CAAO,GAAA,CAAI,EAAE,CAAC,CAAA;AAC3C;AA0BO,SAAS,kBACd,KAAA,EACA,WAAA,EACA,IAAA,mBAA4B,IAAI,KAAI,EACjB;AACnB,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAoB;AACxC,EAAA,MAAM,GAAA,GAAM,CAAC,GAAA,EAA0B,GAAA,KAAgB,GAAA,CAAI,GAAA,CAAI,GAAA,EAAA,CAAM,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,IAAK,CAAA,IAAK,CAAC,CAAA;AAC3F,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG;AACvB,IAAA,IAAA,CAAK,GAAA,CAAI,KAAK,EAAE,CAAA;AAChB,IAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,WAAA;AAC9B,IAAA,IAAI,WAAW,aAAA,EAAe;AAC9B,IAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,IAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,IAAA,IAAA,CAAK,UAAA,CAAW,MAAA,CAAO,OAAA,CAAQ,CAAC,GAAGC,GAAAA,KAAO;AACxC,MAAA,IAAI,CAAA,CAAE,SAAS,OAAA,EAAS,KAAA,CAAM,IAAI,CAAA,CAAE,EAAA,EAAI,EAAE,GAAG,CAAA;AAC7C,MAAA,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,EAAA,EAAIA,GAAE,CAAA;AAAA,IACpB,CAAC,CAAA;AACD,IAAA,IAAI,WAAW,WAAA,EAAa;AAC1B,MAAA,KAAA,MAAW,EAAA,IAAM,WAAW,IAAI,CAAA,MAAO,KAAA,EAAO,KAAA,CAAM,GAAA,CAAI,EAAE,CAAE,CAAA;AAC5D,MAAA;AAAA,IACF;AACA,IAAA,MAAM,QAAA,GAAW,KAAK,QAAA,IAAY,IAAA;AAClC,IAAA,IAAI,aAAa,IAAA,IAAQ,CAAC,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC/C,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAC7B,IAAA,KAAA,MAAW,MAAM,UAAA,CAAW,IAAI,CAAA,EAAG,IAAI,OAAO,QAAA,IAAY,KAAA,CAAM,GAAA,CAAI,EAAE,IAAK,EAAA,EAAI,GAAA,CAAI,OAAO,KAAA,CAAM,GAAA,CAAI,EAAE,CAAE,CAAA;AACxG,IAAA,GAAA,CAAI,KAAA,EAAO,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAE,CAAA;AAC/B,IAAA,GAAA,CAAI,OAAA,EAAS,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAE,CAAA;AAAA,EACnC;AACA,EAAA,OAAO,aAAA,CAAc,aAAa,IAAI,CAAA,CAAE,IAAI,CAAC,EAAE,GAAA,EAAK,KAAA,EAAM,KAAM;AAC9D,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,IAAK,CAAA;AAClC,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,CAAA;AACjC,IAAA,OAAO;AAAA,MACL,GAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA,EAAO,OAAA;AAAA,MACP,OAAA,EAAS,IAAA;AAAA,MACT,SAAS,OAAA,GAAU,IAAA,CAAK,MAAO,IAAA,GAAO,OAAA,GAAW,GAAG,CAAA,GAAI;AAAA,KAC1D;AAAA,EACF,CAAC,CAAA;AACH;AAOO,SAAS,eACd,KAAA,EACA,WAAA,EACA,IAAA,mBAA4B,IAAI,KAAI,EACpB;AAChB,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAI,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAC,CAAA,CAAE,IAAA;AAAA,IACzC,QAAA,EAAU,iBAAA,CAAkB,KAAA,EAAO,WAAA,EAAa,IAAI;AAAA,GACtD;AACF;;;ACxHA,IAAM,6BAAkC,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,YAAA,EAAc,MAAM,CAAC,CAAA;AAEnF,IAAM,QAAA,GAAW,CAAC,IAAA,EAAc,KAAA,KAC9B,SAAS,KAAA,GAAQ,EAAA,GAAK,OAAO,KAAA,GAAQ,KAAK,CAAA,KAAM,QAAA,GAAY,KAAA,CAAM,KAAK,CAAA,GAAe,CAAA;AAGjF,SAAS,UAAA,CACd,IAAA,EACA,IAAA,mBAA4B,IAAI,KAAI,EAChB;AACpB,EAAA,IAAI,MAAA,GAAoC,IAAA;AACxC,EAAA,IAAI,OAAA,GAAyB,IAAA;AAC7B,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,EAAE,KAAA,EAAO,KAAA,EAAO,CAAA,IAAK,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,OAAO,CAAA,EAAG;AAChF,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,EAAG;AACnB,IAAA,MAAM,MAAA,GAAS,gBAAgB,KAAK,CAAA;AACpC,IAAA,IAAI,WAAW,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,IAAY,SAAS,MAAA,EAAQ;AACnE,MAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,MAAM,KAAK,CAAA;AAE5C,MAAA,IAAI,CAAC,MAAA,IAAU,KAAA,GAAQ,GAAA,GAAM,MAAA,CAAO,QAAQ,MAAA,CAAO,GAAA;AACjD,QAAA,MAAA,GAAS,EAAE,KAAA,EAAO,GAAA,EAAK,IAAA,EAAM,MAAM,IAAA,EAAyB;AAAA,IAChE,WAAW,OAAA,KAAY,IAAA,IAAQ,WAAW,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,EAAG;AACzD,MAAA,MAAM,OAAO,MAAA,CAAO,UAAA,CAAW,OAAO,KAAK,CAAC,EAAE,IAAA,EAAK;AACnD,MAAA,IAAI,MAAM,OAAA,GAAU,IAAA;AAAA,IACtB;AAAA,EACF;AACA,EAAA,OAAO,MAAA,GAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAQ,GAAI,IAAA;AAC9C;AAMO,SAAS,aAAA,CACd,KAAA,EACA,OAAA,GAA4E,EAAC,EAC9D;AACf,EAAA,OAAO,KAAA,CACJ,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,MAAW,EAAE,KAAA,EAAO,CAAA,EAAG,OAAA,CAAQ,SAAA,GAAY,IAAI,CAAA,GAAI,IAAA,GAAO,WAAW,IAAA,EAAM,OAAA,CAAQ,IAAI,CAAA,EAAE,CAAE,CAAA,CACtG,MAAA,CAAO,CAAC,CAAA,KAA8C,CAAA,CAAE,CAAA,KAAM,IAAI,CAAA,CAClE,IAAA;AAAA,IAAK,CAAC,GAAG,CAAA,KACR,CAAA,CAAE,EAAE,IAAA,CAAK,IAAA,GAAO,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAA,GAAO,IAAI,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAA,GAAO,CAAA,CAAE,CAAA,CAAE,KAAK,IAAA,GAAO,EAAA,GAAK,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE;AAAA,GACvF,CACC,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,CAAC,CAAA;AACnB;;;ACzBO,SAAS,OACd,IAAA,EACS;AACT,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAW,OAAO,IAAA,CAAK,IAAA;AACzC,EAAA,OACE,IAAA,CAAK,eAAe,IAAA,IACpB,IAAA,CAAK,sBAAsB,IAAA,IAC3B,IAAA,CAAK,sBAAsB,IAAA,CAAK,WAAA;AAEpC;AAGA,IAAM,OAAA,GAAU,gFAAA;AAGT,SAAS,aAAa,KAAA,EAAuB;AAClD,EAAA,MAAM,CAAA,GAAI,MAAM,IAAA,EAAK;AACrB,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,OAAA,CAAQ,GAAA,EAAK,GAAG,CAAC,CAAA,GAAI,MAAA,CAAO,GAAA;AACpE;AAQO,SAAS,gBAAA,CAAiB,IAAA,EAAyB,EAAA,mBAAW,IAAI,MAAK,EAAqB;AACjG,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,UAAA,EAAY,OAAO,UAAA;AACvC,EAAA,IAAI,KAAK,MAAA,KAAW,OAAA,IAAW,IAAA,CAAK,SAAA,KAAc,OAAO,OAAO,OAAA;AAChE,EAAA,IAAI,IAAA,CAAK,QAAQ,OAAO,QAAA;AACxB,EAAA,MAAM,CAAA,GAAI,GAAG,OAAA,EAAQ;AACrB,EAAA,IAAI,KAAK,OAAA,EAAS;AAChB,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA;AAEvC,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA,EAAG,OAAO,QAAA;AAChC,IAAA,IAAI,CAAA,GAAI,OAAO,OAAO,WAAA;AAAA,EACxB;AACA,EAAA,IAAI,KAAK,QAAA,EAAU;AACjB,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,CAAK,QAAQ,CAAA;AACzC,IAAA,IAAI,OAAO,KAAA,CAAM,MAAM,CAAA,IAAK,CAAA,IAAK,QAAQ,OAAO,QAAA;AAAA,EAClD;AACA,EAAA,IAAI,MAAA,CAAO,IAAI,CAAA,EAAG,OAAO,MAAA;AACzB,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,cAAA,CAAe,IAAA,EAAyB,EAAA,mBAAW,IAAI,MAAK,EAAY;AACtF,EAAA,OAAO,gBAAA,CAAiB,IAAA,EAAM,EAAE,CAAA,KAAM,MAAA;AACxC;;;ACrEO,SAAS,cAAA,CACd,cACA,OAAA,EACmC;AACnC,EAAA,MAAM,CAAA,GAAI,OAAA,GAAU,CAAA,cAAA,EAAc,OAAO,CAAA,CAAA,GAAK,EAAA;AAC9C,EAAA,QAAQ,YAAA;AAAc,IACpB,KAAK,MAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,CAAA,IAAA,EAAO,CAAC,CAAA,CAAA,EAAI,MAAM,SAAA,EAAU;AAAA,IAC9C,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,OAAA,EAAQ;AAAA,IACzC,KAAK,QAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,CAAA,MAAA,EAAS,CAAC,CAAA,CAAA,EAAI,MAAM,SAAA,EAAU;AAAA,IAChD,KAAK,WAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,CAAA,SAAA,EAAY,CAAC,CAAA,CAAA,EAAI,MAAM,MAAA,EAAO;AAAA,IAChD,KAAK,QAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,CAAA,MAAA,EAAS,CAAC,CAAA,CAAA,EAAI,MAAM,OAAA,EAAQ;AAAA,IAC9C,KAAK,MAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,CAAA,IAAA,EAAO,CAAC,CAAA,CAAA,EAAI,MAAM,SAAA,EAAU;AAAA,IAC9C,KAAK,UAAA;AACH,MAAA,OAAO,EAAE,KAAA,EAAO,UAAA,EAAY,IAAA,EAAM,OAAA,EAAQ;AAAA;AAEhD;AASO,SAAS,WAAW,UAAA,EAGzB;AACA,EAAA,IAAI,CAAC,UAAA,EAAY,OAAO,EAAE,SAAA,EAAW,CAAA,EAAG,OAAO,CAAA,EAAE;AACjD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,WAAW,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,OAAO,CAAA,CAAE,MAAA;AAAA,IAC/D,QAAQ,UAAA,CAAW,KAAA,EAAO,UAAU,CAAA,KAAM,UAAA,CAAW,SAAS,MAAA,IAAU,CAAA;AAAA,GAC1E;AACF;AAUO,SAAS,YAAA,CACd,EAAA,EACA,MAAA,GAA0F,IAE1F,KAAA,EACe;AACf,EAAA,MAAM,EAAA,GAAK,OAAO,EAAA,KAAO,UAAA,GAAa,EAAA,GAAK,CAAC,GAAA,KAAkB,GAAA,KAAQ,WAAA,GAAc,EAAA,GAAK,CAAA,EAAG,EAAE,QAAQ,GAAG,CAAA,CAAA;AACzG,EAAA,MAAM,IAAA,GAAO,CAAC,EAAA,EAAa,KAAA,EAAe,KAAA,KAAuC;AAC/E,IAAA,MAAM,IAAA,GAAO,QAAQ,EAAE,CAAA;AACvB,IAAA,OAAO;AAAA,MACL,EAAA;AAAA,MACA,EAAA,EAAI,GAAG,EAAE,CAAA;AAAA,MACT,KAAA;AAAA,MACA,GAAI,KAAA,IAAS,IAAA,GAAO,EAAC,GAAI,EAAE,KAAA,EAAM;AAAA,MACjC,GAAI,IAAA,GAAO,EAAE,IAAA,KAAS;AAAC,KACzB;AAAA,EACF,CAAA;AACA,EAAA,OAAO;AAAA,IACL,IAAA,CAAK,WAAA,EAAa,WAAA,EAAa,MAAA,CAAO,SAAS,CAAA;AAAA,IAC/C,IAAA,CAAK,OAAA,EAAS,mBAAA,EAAqB,MAAA,CAAO,KAAK,CAAA;AAAA,IAC/C,IAAA,CAAK,WAAA,EAAa,WAAA,EAAa,MAAA,CAAO,SAAS,CAAA;AAAA,IAC/C,IAAA,CAAK,YAAY,UAAU;AAAA,GAC7B;AACF;AC7DO,IAAM,sBAAA,GAAyB,EAAE,SAAA,EAAW,cAAA;AAG5C,IAAM,qBAAA,GAAwB,EAAE,KAAA,EAAO,gBAAA;AAYvC,IAAM,gBAAA,GAA8CC;AAEpD,IAAM,QAAA,GAA8BC;AAEpC,IAAM,YAAA,GAAsCC;AAE5C,IAAM,YAAA,GAAsCC;AAM5C,SAAS,WAAA,CACd,QAAA,EACA,OAAA,GAA4B,EAAC,EAClB;AACX,EAAA,OAAOC,cAAc,QAAA,EAAU,EAAE,GAAG,sBAAA,EAAwB,GAAG,SAAS,CAAA;AAC1E;AAMO,SAAS,aAAA,CACd,SAAA,EACA,MAAA,GAA0B,EAAC,EACQ;AACnC,EAAA,OAAOC,gBAAgB,SAAA,EAAW,EAAE,GAAG,qBAAA,EAAuB,GAAG,QAAQ,CAAA;AAC3E;;;ACzDO,SAAS,aAAA,CAAc,KAAA,EAAe,QAAA,GAAW,MAAA,EAAgB;AACtE,EAAA,MAAM,IAAA,GAAO,MACV,WAAA,EAAY,CACZ,UAAU,MAAM,CAAA,CAChB,QAAQ,aAAA,EAAe,GAAG,EAC1B,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA,CACtB,KAAA,CAAM,GAAG,EAAE,CAAA,CACX,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AACrB,EAAA,OAAO,IAAA,IAAQ,QAAA;AACjB;AAGO,IAAM,YAAA,GAAe;AAGrB,SAAS,aAAa,IAAA,EAAkC;AAC7D,EAAA,OAAO,YAAA,CAAa,IAAA,CAAK,IAAI,CAAA,GACzB,MAAA,GACA,8EAAA;AACN;AAGO,SAAS,UAAU,KAAA,EAAuB;AAC/C,EAAA,OAAO,CAAA,QAAA,EAAW,KAAK,CAAA,CAAA,CAAG,KAAA,CAAM,GAAG,GAAG,CAAA;AACxC;AAGO,SAAS,QAAA,CAAS,MAAc,KAAA,EAAoC;AACzE,EAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,IAAI,GAAG,OAAO,IAAA;AAC7B,EAAA,KAAA,IAAS,CAAA,GAAI,KAAK,CAAA,EAAA,EAAK;AACrB,IAAA,MAAM,MAAA,GAAS,IAAI,CAAC,CAAA,CAAA;AACpB,IAAA,MAAM,SAAA,GAAY,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,GAAG,EAAA,GAAK,MAAA,CAAO,MAAM,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,GAAG,MAAM,CAAA,CAAA;AAClF,IAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,SAAS,GAAG,OAAO,SAAA;AAAA,EACpC;AACF;;;ACjCO,SAAS,oBAAoB,IAAA,EAIxB;AACV,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,KAAiB,IAAA,IAAQ,CAAC,IAAA,CAAK,SAAA;AACzD,EAAA,OAAO,IAAA,CAAK,aAAA,KAAkB,KAAA,IAAS,CAAC,YAAA;AAC1C","file":"chunk-NQYZ7PHD.js","sourcesContent":["// Turning genesis-forms answers into plain cells and columns. Shared by everything that\n// shows or exports answers: a Sheet or email delivery, a responses table, a CSV. Pure: no\n// storage, no React. Moved up from the host app's src/lib/forms/answers.ts.\nimport {\n summarizeValue,\n type FieldBlock,\n type FormDefinition,\n type Json,\n} from \"@marktiderman/genesis-forms\";\n\nexport type Cell = string | number | boolean;\n\n// carryAnswers moved to genesis-forms (an edit link's prefill runs where the engine does);\n// re-exported so the rules entry keeps it.\nexport { carryAnswers } from \"@marktiderman/genesis-forms\";\n\n// Option labels by value, built once per options array: answerCell runs once per answer, and\n// option lists can hold thousands of options. The first option with a value wins, as find() did.\n// Keys are the stored values as they are (a Map matches them like ===), so number and boolean\n// option values keep their labels too.\nconst labelMaps = new WeakMap<readonly { value: string; label?: string }[], Map<unknown, string | undefined>>();\nfunction optionLabels(options: readonly { value: string; label?: string }[]) {\n let map = labelMaps.get(options);\n if (!map) {\n map = new Map();\n for (const o of options) if (!map.has(o.value)) map.set(o.value, o.label);\n labelMaps.set(options, map);\n }\n return map;\n}\n\n/** One answer as a cell: option labels for choices, Yes/No, lists joined with commas. */\nexport function answerCell(field: FieldBlock, value: Json | undefined): Cell {\n if (value === undefined || value === null) return \"\";\n if (field.type === \"yes-no\")\n return value === true ? \"Yes\" : value === false ? \"No\" : String(value);\n if (field.type === \"consent\")\n return value === true ? \"Agreed\" : value === false ? \"Didn't agree\" : String(value);\n const options = Array.isArray(field.props?.[\"options\"])\n ? (field.props[\"options\"] as { value: string; label?: string }[])\n : [];\n const labels = optionLabels(options);\n const label = (v: Json) => labels.get(v) ?? String(v);\n // Structured values (a worksheet's rows, notes or highlights) use each type's own summary\n // from genesis-forms. Flat values keep raw numbers, so a Sheet can sort and average them.\n const structured = Array.isArray(value)\n ? value.some((v) => v !== null && typeof v === \"object\")\n : typeof value === \"object\";\n if (structured) {\n // A type genesis-forms doesn't know (yet) summarizes as \"[object Object]\": fall back to JSON.\n const summary = summarizeValue(value, field);\n return summary && !summary.includes(\"[object Object]\") ? summary : JSON.stringify(value);\n }\n if (Array.isArray(value)) return value.map(label).join(\", \");\n if (options.length) return label(value);\n return typeof value === \"number\" || typeof value === \"boolean\" ? value : String(value);\n}\n\n/** A label with recall tokens replaced by their fallback. */\nexport const plainLabel = (label: string) =>\n label.replace(/\\{\\{[^}|]*\\|?([^}]*)\\}\\}/g, (_, fallback: string) => fallback || \"…\");\n\nexport interface AnswerColumn {\n /** The field's key: stable across versions, so one column covers every version's answers. */\n key: string;\n label: string;\n}\n\n/**\n * One column per field key across the given definitions, in the order the newest\n * definition asks them, then keys only older versions had (in their order). Labels come\n * from the newest definition that has the key.\n */\nexport function answerColumns(\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): AnswerColumn[] {\n const columns: AnswerColumn[] = [];\n const seen = new Set<string>();\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind !== \"field\" || seen.has(block.key) || skip.has(block.key)) continue;\n seen.add(block.key);\n columns.push({ key: block.key, label: plainLabel(block.label) });\n }\n }\n return columns;\n}\n\n/** A response's answers by field key, as cells (answers are stored by field id). */\nexport function answersByKey(\n definition: FormDefinition,\n answers: Record<string, Json>,\n): Record<string, Cell> {\n const cells: Record<string, Cell> = {};\n for (const block of definition.blocks) {\n if (block.kind !== \"field\") continue;\n const value = answers[block.id];\n if (value !== undefined) cells[block.key] = answerCell(block, value);\n }\n return cells;\n}\n\n/** A response's raw answers by field key, with the field each was given to (answers are stored by field id). */\nexport function valuesByKey(\n definition: FormDefinition,\n answers: Record<string, Json>,\n): Map<string, { field: FieldBlock; value: Json }> {\n const values = new Map<string, { field: FieldBlock; value: Json }>();\n for (const block of definition.blocks) {\n if (block.kind !== \"field\") continue;\n const value = answers[block.id];\n if (value !== undefined && value !== null) values.set(block.key, { field: block, value });\n }\n return values;\n}\n\n/**\n * CSV text (RFC 4180, CRLF) with a header row; every cell is quoted when it needs to be.\n * Text that a spreadsheet would run as a formula (starting with = + - @, tab or CR) gets a\n * leading apostrophe, so a respondent's answer can't run in Excel when staff open the\n * download. Numbers stay as they are. (Sheets delivery writes RAW values and needs none.)\n */\nexport function toCsv(header: readonly string[], rows: readonly (readonly Cell[])[]): string {\n const quote = (v: Cell) => {\n const raw = String(v);\n const s = typeof v === \"string\" && /^[=+\\-@\\t\\r]/.test(raw) ? `'${raw}` : raw;\n return /[\",\\r\\n]/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [header, ...rows].map((r) => r.map(quote).join(\",\")).join(\"\\r\\n\") + \"\\r\\n\";\n}\n","// A form's responses, question by question, as a Summary tab shows them: the average and\n// spread of each rating or NPS question, counts for each choice, the latest text answers.\n// Also the filters a Summary and its table share (dates, extra columns such as a class, a\n// low rating). Built on answers.ts, so every version's answers count under one key. Pure:\n// no storage, no React. Moved up from the host app's src/lib/forms/summary.ts.\nimport {\n choiceOptions,\n isOtherValue,\n otherOption,\n type FieldBlock,\n type FormDefinition,\n type Json,\n} from \"@marktiderman/genesis-forms\";\nimport { answerColumns, answersByKey, valuesByKey, type Cell } from \"./answers\";\n\n/**\n * Where a response is, on a form that saves answers as they go (`settings.saveProgress`):\n * `in_progress` while someone is answering, `partial` once they stopped without sending\n * (kept, and counted like a sent one), `completed` once sent.\n */\nexport type ResponseStatus = \"in_progress\" | \"partial\" | \"completed\";\n\n/** One answered form (a feedback response, a worksheet entry). */\nexport interface SummaryItem {\n id: string;\n /** The day it was answered, YYYY-MM-DD. */\n date: string;\n definition: FormDefinition;\n answers: Record<string, Json>;\n /** Extra plain values a filter can match, such as the location or staff member. */\n extra?: Record<string, Cell>;\n /** Default `completed`. */\n status?: ResponseStatus | undefined;\n /**\n * The furthest question reached (a field id of `definition`), for an unfinished\n * response: genesis-forms `formProgress`'s `fieldId`. Drop-off by question reads it.\n */\n furthest?: string | null | undefined;\n /**\n * Its hidden inputs, as stored. Drop-off by question rebuilds the respondent's path\n * from them and `answers`, so logic that reads a hidden input is followed.\n */\n hidden?: Record<string, Json> | undefined;\n /**\n * Answers the host keeps apart from `answers` (contact details on their own row, say),\n * by field key. Only the path reads them: summaries and filters don't.\n */\n extraAnswers?: Record<string, Json | null | undefined> | undefined;\n}\n\n/**\n * Which responses to show by status. `counted` (the default): sent and partial ones,\n * which summaries count; `in_progress` ones are still being answered.\n */\nexport type StatusFilter = \"counted\" | \"completed\" | \"partial\" | \"in_progress\";\n\n/** The status filter's words, in the menu's order. */\nexport const STATUS_FILTER_LABEL: Record<StatusFilter, string> = {\n counted: \"Sent and partial\",\n completed: \"Sent\",\n partial: \"Partial\",\n in_progress: \"In progress\",\n};\n\n/** A response status's word, as a table or a detail panel shows it. */\nexport const RESPONSE_STATUS_LABEL: Record<ResponseStatus, string> = {\n in_progress: \"In progress\",\n partial: \"Partial\",\n completed: \"Sent\",\n};\n\n/** Whether `item` passes a status filter (no status is `completed`). */\nexport function matchesStatus(item: Pick<SummaryItem, \"status\">, filter: StatusFilter = \"counted\"): boolean {\n const status = item.status ?? \"completed\";\n return filter === \"counted\" ? status !== \"in_progress\" : status === filter;\n}\n\nexport interface ScaleSummary {\n kind: \"scale\";\n key: string;\n label: string;\n type: \"rating\" | \"nps\";\n /** The field type, as for every summary. */\n fieldType: \"rating\" | \"nps\";\n /** How many responses answered it. */\n count: number;\n min: number;\n max: number;\n /** Null when no one answered. */\n average: number | null;\n /** One per value from min to max, in order, zeros included. */\n buckets: { value: number; count: number }[];\n /**\n * Answers given on an older version's different scale (a 1–10 rating now 1–5), moved\n * onto this one in proportion: they count, at their nearest point on this scale.\n */\n rescaled: number;\n /** Answers left out: outside their own question's scale, or not a whole number. */\n excluded: number;\n /** NPS only: promoters 9–10, passives 7–8, detractors 0–6, score = % promoters − % detractors. */\n nps: { promoters: number; passives: number; detractors: number; score: number } | null;\n}\n\nexport interface ChoiceSummary {\n kind: \"choice\";\n key: string;\n label: string;\n /** single-choice, multi-choice, dropdown, yes-no or consent. */\n fieldType: string;\n /** How many responses answered it. */\n count: number;\n /** Several options per response, so the percentages can add up to more than 100. */\n multiple: boolean;\n /** The newest version's options in order, then any only older versions had. */\n options: { value: string; label: string; count: number; percent: number }[];\n}\n\nexport interface TextSummary {\n kind: \"text\";\n key: string;\n label: string;\n /** The field type: short-text, long-text, email… */\n fieldType: string;\n count: number;\n /** Every answer, newest day first. */\n answers: { id: string; date: string; text: string }[];\n}\n\nexport type QuestionSummary = ScaleSummary | ChoiceSummary | TextSummary;\n\nconst CHOICE_TYPES: ReadonlySet<string> = new Set([\n \"single-choice\",\n \"multi-choice\",\n \"dropdown\",\n \"yes-no\",\n \"consent\",\n]);\nconst YES_NO = [\n { value: \"true\", label: \"Yes\" },\n { value: \"false\", label: \"No\" },\n];\nconst CONSENT = [\n { value: \"true\", label: \"Agreed\" },\n { value: \"false\", label: \"Didn't agree\" },\n];\n\n/** The summary row that counts a question's typed \"Other\" answers. */\nexport const OTHER_BUCKET = \"__other__\";\n\nconst optionsOf = (field: FieldBlock) =>\n field.type === \"yes-no\"\n ? YES_NO\n : field.type === \"consent\"\n ? CONSENT\n : choiceOptions(field).map((o) => ({ value: o.value, label: o.label ?? o.value }));\n\nconst ratingMax = (field: FieldBlock) => {\n const max = field.props?.[\"max\"];\n return typeof max === \"number\" && Number.isInteger(max) && max >= 1 && max <= 100 ? max : 5;\n};\n\n/** A rating or NPS question's own scale; null for other questions. */\nconst scaleOf = (field: FieldBlock): { min: number; max: number } | null =>\n field.type === \"nps\" ? { min: 0, max: 10 } : field.type === \"rating\" ? { min: 1, max: ratingMax(field) } : null;\n\nconst newestFirst = <T extends { date: string }>(items: readonly T[]) =>\n items\n .map((item, index) => ({ item, index }))\n .sort((x, y) =>\n x.item.date < y.item.date ? 1 : x.item.date > y.item.date ? -1 : x.index - y.index,\n )\n .map((x) => x.item);\n\n/**\n * One summary per question across `definitions` (newest first: it sets the order, labels,\n * type and options), counting each item's answers by field key. Keys in `skip` are left out.\n */\nexport function summarizeResponses(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): QuestionSummary[] {\n const newest = new Map<string, FieldBlock>();\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind === \"field\" && !newest.has(block.key)) newest.set(block.key, block);\n }\n }\n const answered = newestFirst(items).map((item) => ({\n item,\n values: valuesByKey(item.definition, item.answers),\n cells: answersByKey(item.definition, item.answers),\n }));\n\n return answerColumns(definitions, skip).flatMap((column): QuestionSummary[] => {\n const field = newest.get(column.key);\n if (!field) return [];\n const { key, label } = column;\n\n if (field.type === \"rating\" || field.type === \"nps\") {\n const nps = field.type === \"nps\";\n // The newest version sets the scale. One pass: a bucket array, never a spread of\n // every answer (that overflows the stack on large forms).\n const min = nps ? 0 : 1;\n const max = nps ? 10 : ratingMax(field);\n const counts = new Array<number>(max - min + 1).fill(0);\n let count = 0;\n let sum = 0;\n let promoters = 0;\n let detractors = 0;\n let rescaled = 0;\n let excluded = 0;\n for (const { values } of answered) {\n const answer = values.get(key);\n if (!answer) continue;\n const v = answer.value;\n const own = scaleOf(answer.field);\n if (!own || typeof v !== \"number\" || !Number.isInteger(v) || v < own.min || v > own.max) {\n excluded++;\n continue;\n }\n let x = v;\n if (own.min !== min || own.max !== max) {\n // Another version's scale: the same share of the way along this one.\n x = own.max === own.min ? max : min + ((v - own.min) * (max - min)) / (own.max - own.min);\n rescaled++;\n }\n const point = Math.round(x);\n counts[point - min]! += 1;\n count++;\n sum += x;\n if (point >= 9) promoters++;\n else if (point <= 6) detractors++;\n }\n return [\n {\n kind: \"scale\",\n key,\n label,\n type: field.type,\n fieldType: field.type,\n count,\n min,\n max,\n average: count ? sum / count : null,\n buckets: counts.map((c, i) => ({ value: min + i, count: c })),\n rescaled,\n excluded,\n nps:\n nps && count\n ? {\n promoters,\n passives: count - promoters - detractors,\n detractors,\n score: Math.round(((promoters - detractors) / count) * 100),\n }\n : null,\n },\n ];\n }\n\n if (CHOICE_TYPES.has(field.type)) {\n const options = optionsOf(field).map((o) => ({ ...o, count: 0 }));\n // Lookups by value, not options.find per answer: option lists can hold thousands.\n const byValue = new Map<string, (typeof options)[number]>();\n for (const o of options) if (!byValue.has(o.value)) byValue.set(o.value, o);\n const add = (option: (typeof options)[number]) => {\n options.push(option);\n byValue.set(option.value, option);\n return option;\n };\n const oldOptions = new Map<FieldBlock, Map<string, { label?: string }>>();\n const oldOption = (from: FieldBlock, value: string) => {\n let map = oldOptions.get(from);\n if (!map) {\n map = new Map();\n for (const o of optionsOf(from)) if (!map.has(o.value)) map.set(o.value, o);\n oldOptions.set(from, map);\n }\n return map.get(value);\n };\n const find = (value: string, from: FieldBlock) => {\n const known = byValue.get(value);\n if (known) return known;\n // Typed \"Other\" answers count together, under the question's Other label. (Checked only\n // for values not already counted: isOtherValue looks through the question's options.)\n if (isOtherValue(from, value)) {\n return (\n byValue.get(OTHER_BUCKET) ??\n add({ value: OTHER_BUCKET, label: (otherOption(field) ?? otherOption(from))!.label, count: 0 })\n );\n }\n // An option only an older version had: its label from that version.\n return add({ value, label: oldOption(from, value)?.label ?? value, count: 0 });\n };\n let count = 0;\n for (const { values } of answered) {\n const answer = values.get(key);\n if (!answer) continue;\n const chosen = (Array.isArray(answer.value) ? answer.value : [answer.value]).filter(\n (v): v is string | boolean => typeof v === \"string\" || typeof v === \"boolean\",\n );\n if (!chosen.length) continue;\n count++;\n for (const v of new Set(chosen.map(String))) find(v, answer.field).count++;\n }\n return [\n {\n kind: \"choice\",\n key,\n label,\n fieldType: field.type,\n count,\n multiple: field.type === \"multi-choice\",\n options: options.map((o) => ({ ...o, percent: count ? (o.count / count) * 100 : 0 })),\n },\n ];\n }\n\n const answers = answered.flatMap(({ item, cells }) => {\n const text = String(cells[key] ?? \"\").trim();\n return text ? [{ id: item.id, date: item.date, text }] : [];\n });\n return [{ kind: \"text\", key, label, fieldType: field.type, count: answers.length, answers }];\n });\n}\n\n/** The highest score any rating question in `definitions` asks for (NPS left out); null when none. */\nexport function highestRating(definitions: readonly FormDefinition[]): number | null {\n let max: number | null = null;\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind === \"field\" && block.type === \"rating\")\n max = Math.max(max ?? 0, ratingMax(block));\n }\n }\n return max;\n}\n\n/** The lowest rating-question answer in an item (NPS left out), or null when it has none. */\nexport function lowestRating(item: SummaryItem): number | null {\n let lowest: number | null = null;\n for (const { field, value } of valuesByKey(item.definition, item.answers).values()) {\n if (field.type === \"rating\" && typeof value === \"number\" && (lowest === null || value < lowest))\n lowest = value;\n }\n return lowest;\n}\n\n/** \"Low\" is the bottom 40% of a rating's scale: 2 or below out of 5, 4 or below out of 10. */\nconst LOW_SHARE = 0.4;\n/** NPS detractors: 0 to 6. */\nconst NPS_LOW = 6;\n\n/**\n * The highest answer that counts as low on a rating or NPS question: the bottom 40% of a\n * rating's scale (at least 1), or 0–6 (detractors) on NPS. Null for other questions.\n */\nexport function lowRatingAtMost(field: FieldBlock): number | null {\n if (field.type === \"nps\") return NPS_LOW;\n if (field.type !== \"rating\") return null;\n return lowScaleAtMost(\"rating\", ratingMax(field));\n}\n\n/** lowRatingAtMost for a scale known only by its type and top score (a ScaleSummary's). */\nexport function lowScaleAtMost(type: \"rating\" | \"nps\", max: number): number {\n return type === \"nps\" ? NPS_LOW : Math.max(1, Math.floor(max * LOW_SHARE));\n}\n\n/** Whether any rating or NPS answer in an item is low on its own question's scale. */\nexport function hasLowRating(item: SummaryItem): boolean {\n return hasLowRatingExcept(item, new Set());\n}\n\n/** hasLowRating, leaving out the answers to keys in `skip` (as summaries and needsFollowUp do). */\nexport function hasLowRatingExcept(item: SummaryItem, skip: ReadonlySet<string>): boolean {\n for (const [key, { field, value }] of valuesByKey(item.definition, item.answers)) {\n if (skip.has(key)) continue;\n const atMost = lowRatingAtMost(field);\n if (atMost !== null && typeof value === \"number\" && value <= atMost) return true;\n }\n return false;\n}\n\n/**\n * What \"low\" means across `definitions`, in words: \"2 or below\" for one 1–5 scale, \"2 or\n * below out of 5, 4 or below out of 10\" for two, \"0–6 on NPS\" beside them (\"0–6\" alone).\n * Null when no question has a rating or NPS answer.\n */\nexport function lowRatingLabel(definitions: readonly FormDefinition[]): string | null {\n const scales = new Set<number>();\n let nps = false;\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind !== \"field\") continue;\n if (block.type === \"nps\") nps = true;\n else if (block.type === \"rating\") scales.add(ratingMax(block));\n }\n }\n const several = scales.size + (nps ? 1 : 0) > 1;\n const parts = [...scales]\n .sort((a, b) => a - b)\n .map((max) => {\n const atMost = Math.max(1, Math.floor(max * LOW_SHARE));\n return several ? `${atMost} or below out of ${max}` : `${atMost} or below`;\n });\n if (nps) parts.push(several ? `0–${NPS_LOW} on NPS` : `0–${NPS_LOW}`);\n return parts.length ? parts.join(\", \") : null;\n}\n\nexport interface ResponseFilter {\n /** First and last day, YYYY-MM-DD, both included; open-ended when absent. */\n from?: string | null;\n to?: string | null;\n /** Extra values that must match exactly, such as { class: \"6am WOD\" }. */\n match?: Record<string, string | null | undefined>;\n /** Only items with a rating at or below this (any rating question). */\n ratingAtMost?: number | null;\n /** Only items with a low answer on its question's own scale (hasLowRating). */\n low?: boolean;\n /** By status (matchesStatus); default `counted`: sent and partial, not in progress. */\n status?: StatusFilter | undefined;\n}\n\n/** Whether a filter leaves anything out beyond the default (in-progress responses). */\nexport function isFiltered(filter: ResponseFilter): boolean {\n return Boolean(\n filter.from ||\n filter.to ||\n filter.ratingAtMost != null ||\n filter.low ||\n (filter.status && filter.status !== \"counted\") ||\n Object.values(filter.match ?? {}).some((v) => v != null && v !== \"\"),\n );\n}\n\n/** The items a filter keeps, in their order. */\nexport function filterResponses<T extends SummaryItem>(\n items: readonly T[],\n filter: ResponseFilter,\n): T[] {\n const match = Object.entries(filter.match ?? {}).filter(\n (e): e is [string, string] => e[1] != null && e[1] !== \"\",\n );\n return items.filter((item) => {\n if (!matchesStatus(item, filter.status)) return false;\n if (filter.from && item.date < filter.from) return false;\n if (filter.to && item.date > filter.to) return false;\n if (match.some(([key, value]) => String(item.extra?.[key] ?? \"\") !== value)) return false;\n if (filter.ratingAtMost != null) {\n const lowest = lowestRating(item);\n if (lowest === null || lowest > filter.ratingAtMost) return false;\n }\n if (filter.low && !hasLowRating(item)) return false;\n return true;\n });\n}\n\nexport type DatePreset = \"all\" | \"today\" | \"week\" | \"7d\" | \"30d\" | \"month\";\n\nconst addDays = (day: string, n: number) => {\n const t = Date.parse(`${day}T00:00:00Z`) + n * 86_400_000;\n return new Date(t).toISOString().slice(0, 10);\n};\n\n/**\n * A preset's first and last day, given today (YYYY-MM-DD, on the clock the items' days\n * use). \"week\" starts on Monday; \"7d\" and \"30d\" include today.\n */\nexport function presetRange(\n preset: DatePreset,\n today: string,\n): { from: string | null; to: string | null } {\n switch (preset) {\n case \"all\":\n return { from: null, to: null };\n case \"today\":\n return { from: today, to: today };\n case \"week\": {\n const weekday = new Date(`${today}T00:00:00Z`).getUTCDay(); // 0 is Sunday\n return { from: addDays(today, -((weekday + 6) % 7)), to: today };\n }\n case \"7d\":\n return { from: addDays(today, -6), to: today };\n case \"30d\":\n return { from: addDays(today, -29), to: today };\n case \"month\":\n return { from: `${today.slice(0, 7)}-01`, to: today };\n }\n}\n\n// The filter bar ----------------------------------------------------------------------------\n\n/** What the filter bar holds; `toResponseFilter` turns it into a filter. */\nexport interface FiltersValue {\n when: DatePreset | \"custom\";\n /** Custom range, YYYY-MM-DD; empty for open-ended. */\n from: string;\n to: string;\n /** By choice filter key, e.g. { class: \"6am WOD\" }; missing or empty for any. */\n match: Record<string, string>;\n ratingAtMost: number | null;\n /** Low ratings, each on its own question's scale (lowRatingAtMost). */\n low: boolean;\n /** By status, on a form that saves answers as they go; missing is `counted`. */\n status?: StatusFilter | undefined;\n}\n\nexport const NO_FILTERS: FiltersValue = {\n when: \"all\",\n from: \"\",\n to: \"\",\n match: {},\n ratingAtMost: null,\n low: false,\n};\n\n/** The filter for `value`, given today's date on the clock the responses' days use. */\nexport function toResponseFilter(value: FiltersValue, today: string): ResponseFilter {\n const range =\n value.when === \"custom\"\n ? { from: value.from || null, to: value.to || null }\n : presetRange(value.when, today);\n return {\n ...range,\n match: value.match,\n ratingAtMost: value.ratingAtMost,\n low: value.low,\n ...(value.status ? { status: value.status } : {}),\n };\n}\n\n/**\n * The one-click \"Low ratings this week\": this week, and low on each question's own scale\n * (lowRatingAtMost: the bottom 40% of a rating, NPS detractors), other filters kept.\n */\nexport const lowThisWeek = (value: FiltersValue): FiltersValue => ({\n ...value,\n when: \"week\",\n low: true,\n});\n","// The Responses tab's headline numbers: how many responses (and the change against the\n// period before), the average of the form's main rating, how many have a low rating, and\n// the rate of the form's first consent or yes/no question. Built on summary.ts. Pure.\nimport type { FormDefinition } from \"@marktiderman/genesis-forms\";\nimport type { HeadlineNumber } from \"@marktiderman/genesis-ui/resource\";\nimport {\n hasLowRatingExcept,\n presetRange,\n summarizeResponses,\n type FiltersValue,\n type ResponseFilter,\n type SummaryItem,\n} from \"./summary\";\n\nexport interface Headline {\n responses: {\n count: number;\n /** Responses in the period before, under the same other filters; null with no period. */\n previous: number | null;\n /** count − previous; null with no period. */\n change: number | null;\n /** How many of `count` are partial (never sent); left out when there are none. */\n partial?: number;\n };\n /** The first rating question (newest definition order); null when the form has none. */\n rating: {\n key: string;\n label: string;\n max: number;\n /** Null when nobody answered it. */\n average: number | null;\n /** The same question's average in the period before; null without one or without answers. */\n previousAverage: number | null;\n /** average − previousAverage, when both are known. */\n change: number | null;\n } | null;\n /** Responses with a low answer on any rating or NPS question; null when there is none. */\n low: { count: number } | null;\n /** The first consent question, else the first yes/no one; null when there is none. */\n rate: {\n key: string;\n label: string;\n type: \"consent\" | \"yes-no\";\n /** Agreed or Yes. */\n yes: number;\n /** How many answered it. */\n count: number;\n /** 0–100; null when nobody answered. */\n percent: number | null;\n } | null;\n}\n\n/**\n * The headline numbers for `items` (already filtered), with `previous` (the same filters\n * over the period before, from `comparisonFilter`) for the changes. `definitions` are\n * newest first, as `summarizeResponses` takes them; `skip` leaves keys out.\n */\nexport function headlineNumbers(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n options: { previous?: readonly SummaryItem[] | null; skip?: ReadonlySet<string> } = {},\n): Headline {\n const previous = options.previous ?? null;\n const summaries = summarizeResponses(items, definitions, options.skip);\n const partial = items.filter((i) => i.status === \"partial\").length;\n const before = previous ? summarizeResponses(previous, definitions, options.skip) : null;\n\n const scale = summaries.find((s) => s.kind === \"scale\" && s.type === \"rating\");\n let rating: Headline[\"rating\"] = null;\n if (scale && scale.kind === \"scale\") {\n const old = before?.find((s) => s.kind === \"scale\" && s.key === scale.key);\n const previousAverage = old && old.kind === \"scale\" ? old.average : null;\n rating = {\n key: scale.key,\n label: scale.label,\n max: scale.max,\n average: scale.average,\n previousAverage,\n change:\n scale.average !== null && previousAverage !== null\n ? Math.round((scale.average - previousAverage) * 10) / 10\n : null,\n };\n }\n\n const scored = summaries.some((s) => s.kind === \"scale\");\n const choice =\n summaries.find((s) => s.kind === \"choice\" && s.fieldType === \"consent\") ??\n summaries.find((s) => s.kind === \"choice\" && s.fieldType === \"yes-no\");\n let rate: Headline[\"rate\"] = null;\n if (choice && choice.kind === \"choice\") {\n const yes = choice.options.find((o) => o.value === \"true\")?.count ?? 0;\n rate = {\n key: choice.key,\n label: choice.label,\n type: choice.fieldType as \"consent\" | \"yes-no\",\n yes,\n count: choice.count,\n percent: choice.count ? Math.round((yes / choice.count) * 100) : null,\n };\n }\n\n return {\n responses: {\n count: items.length,\n previous: previous ? previous.length : null,\n change: previous ? items.length - previous.length : null,\n ...(partial ? { partial } : {}),\n },\n rating,\n // The same skip as needsFollowUp, so the Low ratings card and the follow-up list agree.\n low: scored ? { count: items.filter((i) => hasLowRatingExcept(i, options.skip ?? new Set())).length } : null,\n rate,\n };\n}\n\nconst addDays = (day: string, n: number) =>\n new Date(Date.parse(`${day}T00:00:00Z`) + n * 86_400_000).toISOString().slice(0, 10);\nconst daysBetween = (from: string, to: string) =>\n Math.round((Date.parse(`${to}T00:00:00Z`) - Date.parse(`${from}T00:00:00Z`)) / 86_400_000);\n\n/**\n * The period before the one the filter bar picks, with the bar's other filters kept, and\n * what to call it (\"last week\"). \"This week\" compares with the same weekdays last week,\n * \"This month\" with last month up to the same day, any other range with as many days\n * just before it. Null for \"All time\", or a\n * custom range with an open end.\n */\nexport function comparisonFilter(\n value: FiltersValue,\n today: string,\n): { filter: ResponseFilter; label: string } | null {\n const range =\n value.when === \"custom\"\n ? { from: value.from || null, to: value.to || null }\n : presetRange(value.when, today);\n if (!range.from || !range.to || range.to < range.from) return null;\n let from: string;\n let to: string;\n if (value.when === \"month\") {\n const first = `${range.from.slice(0, 7)}-01`;\n const lastMonth = addDays(first, -1); // the last day of last month\n from = `${lastMonth.slice(0, 7)}-01`;\n const day = Math.min(Number(range.to.slice(8, 10)), Number(lastMonth.slice(8, 10)));\n to = `${lastMonth.slice(0, 7)}-${String(day).padStart(2, \"0\")}`;\n } else if (value.when === \"week\") {\n // Monday to today, against the same weekdays last week.\n from = addDays(range.from, -7);\n to = addDays(range.to, -7);\n } else {\n const length = daysBetween(range.from, range.to) + 1;\n to = addDays(range.from, -1);\n from = addDays(range.from, -length);\n }\n const label =\n value.when === \"today\"\n ? \"yesterday\"\n : value.when === \"week\"\n ? \"last week\"\n : value.when === \"month\"\n ? \"last month\"\n : value.when === \"7d\"\n ? \"the 7 days before\"\n : value.when === \"30d\"\n ? \"the 30 days before\"\n : \"the days before\";\n return {\n filter: {\n from,\n to,\n match: value.match,\n ratingAtMost: value.ratingAtMost,\n low: value.low,\n ...(value.status ? { status: value.status } : {}),\n },\n label,\n };\n}\n\nconst signed = (n: number, digits = 0) => {\n const s = Math.abs(n).toFixed(digits);\n return n > 0 ? `+${s}` : n < 0 ? `−${s}` : s;\n};\n\n/**\n * The cards for `headlineNumbers`' answer: Responses (with the change against `period`,\n * e.g. \"last week\"), Average rating, Low ratings, and the consent or yes/no rate. A card\n * the form has no question for is left out.\n */\nexport function headlineCards(\n headline: Headline,\n options: {\n period?: string | null | undefined;\n /** How many low-rated responses still need a follow-up (not handled); the card says so. */\n lowOpen?: number | undefined;\n } = {},\n): HeadlineNumber[] {\n const cards: HeadlineNumber[] = [];\n const { responses, rating, low, rate } = headline;\n // Partial responses count, and the card says how many there are.\n const partial = responses.partial ? `${responses.partial} partial` : null;\n cards.push({\n key: \"responses\",\n label: \"Responses\",\n value: responses.count,\n ...(responses.change !== null && options.period\n ? {\n detail:\n (responses.change === 0 ? `Same as ${options.period}` : `${signed(responses.change)} vs ${options.period}`) +\n (partial ? ` · ${partial}` : \"\"),\n tone: responses.change > 0 ? (\"positive\" as const) : responses.change < 0 ? (\"negative\" as const) : (\"muted\" as const),\n }\n : partial\n ? { detail: `Including ${partial}` }\n : {}),\n });\n if (rating) {\n const change = rating.change;\n cards.push({\n key: \"rating\",\n label: \"Average rating\",\n value: rating.average === null ? \"–\" : `${rating.average.toFixed(1)} / ${rating.max}`,\n ...(change !== null && options.period\n ? {\n detail: change === 0 ? `Same as ${options.period}` : `${change > 0 ? \"Up\" : \"Down\"} ${Math.abs(change).toFixed(1)}`,\n tone: change > 0 ? (\"positive\" as const) : change < 0 ? (\"warning\" as const) : (\"muted\" as const),\n }\n : rating.average === null\n ? { detail: \"No ratings yet\" }\n : {}),\n });\n }\n if (low) {\n const open = options.lowOpen ?? low.count;\n cards.push({\n key: \"low\",\n label: \"Low ratings\",\n value: low.count,\n ...(open\n ? { detail: open === 1 ? \"Needs a follow-up\" : `${open} need a follow-up`, tone: \"negative\" as const }\n : { detail: low.count ? \"All followed up\" : \"None\" }),\n });\n }\n if (rate) {\n cards.push({\n key: \"rate\",\n label: rate.label || (rate.type === \"consent\" ? \"Agreed\" : \"Yes\"),\n value: rate.percent === null ? \"–\" : `${rate.percent}%`,\n detail: rate.count\n ? `${rate.yes} of ${rate.count} ${rate.type === \"consent\" ? \"agreed\" : \"said yes\"}`\n : \"No answers yet\",\n });\n }\n return cards;\n}\n","// Drop-off by question (Typeform's \"question-by-question insights\"), for a form that saves\n// answers as they go: for each question, how many people reached it and how many stopped\n// there without sending. Worked out on each respondent's own path, rebuilt with genesis-forms\n// `computePath` from what a response keeps, and its furthest question. Pure.\nimport { computePath, type FieldBlock, type FormDefinition, type Json } from \"@marktiderman/genesis-forms\";\nimport { answerColumns } from \"./answers\";\nimport type { SummaryItem } from \"./summary\";\n\nexport interface QuestionDropOff {\n key: string;\n label: string;\n /** How many responses reached this question (it was on their path, on screen or answered). */\n views: number;\n /** How many stopped here: their furthest question, never sent. */\n stopped: number;\n /** stopped ÷ views as a whole percentage; null when nobody reached it. */\n dropOff: number | null;\n}\n\nexport interface DropOffSummary {\n /**\n * How many people started: distinct responses of any status (sent, partial, in progress),\n * each once. Someone is saved once they answer a question or move on from the first.\n */\n started: number;\n /** Each question's views and drop-off (`dropOffByQuestion`). */\n dropOffs: QuestionDropOff[];\n}\n\n/**\n * The field ids on a response's path, in order: genesis-forms `computePath` over its\n * `answers` (by field id), its `hidden` inputs and its `extraAnswers` (by field key).\n */\nfunction pathFields(item: SummaryItem): string[] {\n const { definition } = item;\n const fields = new Map<string, FieldBlock>();\n for (const block of definition.blocks) if (block.kind === \"field\") fields.set(block.id, block);\n const values: Record<string, Json | undefined> = { ...item.answers };\n if (item.extraAnswers) {\n for (const field of fields.values()) {\n const kept = Object.prototype.hasOwnProperty.call(item.extraAnswers, field.key)\n ? item.extraAnswers[field.key]\n : undefined;\n // A null in `answers` is a placeholder for a value kept apart: the extra one fills it.\n if (kept != null && values[field.id] == null) values[field.id] = kept;\n }\n }\n const { path } = computePath(definition, { values, hidden: item.hidden ?? {}, fields });\n return path.filter((id) => fields.has(id));\n}\n\n/**\n * Each question's views and drop-off, in the newest definition's order (`definitions`\n * newest first, as `summarizeResponses` takes them), matched across versions by field key.\n * Each response counts once (by `id`).\n *\n * - A sent response (`completed`, or no status) reached every question on its path and\n * stopped at none. A question logic hid or jumped over for them was never reached.\n * - A `partial` response reached the questions on its path before its `furthest` (the\n * path is rebuilt from the answers so far, so it can run past it), then `furthest`, and\n * stopped there. One without `furthest` (saved before it was kept) is left out.\n * - An `in_progress` response is left out: they may still be answering.\n *\n * The path is rebuilt from `answers`, `hidden` and `extraAnswers`; give the item every\n * answer logic can read, or a rule reading a missing one sees it unanswered. Two things a\n * stored response can't tell, so they count as on the path:\n *\n * - A question a prefilled link answered and hid (`props.prefill.hideWhenPrefilled`):\n * which answers came from the link lives in the form's answer events, which aren't kept.\n * - A rule comparing a pick from a host-supplied option list to an option value, when the\n * host stores the pick as its label: the rule sees the label.\n *\n * Someone who opened the form and left before moving on from the first question was\n * never saved, so they aren't counted.\n */\nexport function dropOffByQuestion(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): QuestionDropOff[] {\n const views = new Map<string, number>();\n const stopped = new Map<string, number>();\n const add = (map: Map<string, number>, key: string) => map.set(key, (map.get(key) ?? 0) + 1);\n const seen = new Set<string>();\n for (const item of items) {\n if (seen.has(item.id)) continue;\n seen.add(item.id);\n const status = item.status ?? \"completed\";\n if (status === \"in_progress\") continue;\n const keyOf = new Map<string, string>();\n const order = new Map<string, number>();\n item.definition.blocks.forEach((b, at) => {\n if (b.kind === \"field\") keyOf.set(b.id, b.key);\n order.set(b.id, at);\n });\n if (status === \"completed\") {\n for (const id of pathFields(item)) add(views, keyOf.get(id)!);\n continue;\n }\n const furthest = item.furthest ?? null;\n if (furthest === null || !keyOf.has(furthest)) continue;\n const at = order.get(furthest)!;\n for (const id of pathFields(item)) if (id !== furthest && order.get(id)! < at) add(views, keyOf.get(id)!);\n add(views, keyOf.get(furthest)!);\n add(stopped, keyOf.get(furthest)!);\n }\n return answerColumns(definitions, skip).map(({ key, label }) => {\n const reached = views.get(key) ?? 0;\n const left = stopped.get(key) ?? 0;\n return {\n key,\n label,\n views: reached,\n stopped: left,\n dropOff: reached ? Math.round((left / reached) * 100) : null,\n };\n });\n}\n\n/**\n * What `<DropOffByQuestion>` shows: how many people started and each question's drop-off.\n * Pass every response under the host's filters except status (in-progress ones count as\n * started, never per question).\n */\nexport function dropOffSummary(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): DropOffSummary {\n return {\n started: new Set(items.map((i) => i.id)).size,\n dropOffs: dropOffByQuestion(items, definitions, skip),\n };\n}\n","// Which responses need a follow-up (a low rating, not handled yet), with the low score\n// and the first written comment each one has. Pure.\nimport { answerCell, valuesByKey } from \"./answers\";\nimport { lowRatingAtMost, type SummaryItem } from \"./summary\";\n\nexport interface FollowUp<T extends SummaryItem = SummaryItem> {\n item: T;\n /** The lowest low answer, on its own question's scale. */\n rating: { value: number; max: number; type: \"rating\" | \"nps\" };\n /** The first written answer (short or long text), trimmed; null when there is none. */\n comment: string | null;\n}\n\nconst TEXT_TYPES: ReadonlySet<string> = new Set([\"long-text\", \"short-text\", \"text\"]);\n\nconst scaleMax = (type: string, props: Record<string, unknown> | undefined) =>\n type === \"nps\" ? 10 : typeof props?.[\"max\"] === \"number\" ? (props[\"max\"] as number) : 5;\n\n/** One item's follow-up, or null when none of its answers is low. */\nexport function followUpOf<T extends SummaryItem>(\n item: T,\n skip: ReadonlySet<string> = new Set(),\n): FollowUp<T> | null {\n let rating: FollowUp[\"rating\"] | null = null;\n let comment: string | null = null;\n for (const [key, { field, value }] of valuesByKey(item.definition, item.answers)) {\n if (skip.has(key)) continue;\n const atMost = lowRatingAtMost(field);\n if (atMost !== null && typeof value === \"number\" && value <= atMost) {\n const max = scaleMax(field.type, field.props);\n // The lowest share of its scale wins: a 2 of 5 is lower than a 4 of 10.\n if (!rating || value / max < rating.value / rating.max)\n rating = { value, max, type: field.type as \"rating\" | \"nps\" };\n } else if (comment === null && TEXT_TYPES.has(field.type)) {\n const text = String(answerCell(field, value)).trim();\n if (text) comment = text;\n }\n }\n return rating ? { item, rating, comment } : null;\n}\n\n/**\n * The items that need a follow-up, newest day first: a low answer on a rating or NPS\n * question (lowRatingAtMost), and not handled yet. `skip` leaves keys out (contact details).\n */\nexport function needsFollowUp<T extends SummaryItem>(\n items: readonly T[],\n options: { isHandled?: (item: T) => boolean; skip?: ReadonlySet<string> } = {},\n): FollowUp<T>[] {\n return items\n .map((item, index) => ({ index, f: options.isHandled?.(item) ? null : followUpOf(item, options.skip) }))\n .filter((x): x is { index: number; f: FollowUp<T> } => x.f !== null)\n .sort((x, y) =>\n x.f.item.date < y.f.item.date ? 1 : x.f.item.date > y.f.item.date ? -1 : x.index - y.index,\n )\n .map((x) => x.f);\n}\n","// Whether a form is taking responses, and if not why: the one rule every surface uses\n// (the public page and its submit endpoint, a forms list, the form's header and\n// settings). Generic form settings (status, opening and closing times, paused and a\n// response cap). Pure. Moved up from the host app's src/lib/forms/availability.ts; an app\n// that stores forms should apply the same rule on save.\n\nexport type FormAvailability =\n \"draft\" | \"archived\" | \"paused\" | \"scheduled\" | \"closed\" | \"full\" | \"live\";\n\nexport interface AvailabilityInput {\n status: \"draft\" | \"active\" | \"archived\";\n /** False when the form has never been published (it has no version to serve). */\n published?: boolean;\n /**\n * ISO times it takes responses from and until; open-ended when absent. Each needs `Z` or\n * an offset (`+02:00`): a time without one would be read on whatever clock the code runs\n * on. One that doesn't parse, or has no offset, keeps the form closed (fail closed).\n * Normalise times where they are written (`new Date(…).toISOString()`).\n */\n opensAt?: string | null | undefined;\n closesAt?: string | null | undefined;\n paused?: boolean | undefined;\n /** At most this many completed responses; null or absent for no cap. */\n responseCap?: number | null | undefined;\n /** Completed, non-deleted responses so far, when the caller knows the count. */\n completedResponses?: number | null | undefined;\n /** Whether the cap is reached, when only that is known (the public page never sees the count). */\n full?: boolean | undefined;\n}\n\n/** Whether the form has its response cap: from `full` when given, else from the cap and count. */\nexport function isFull(\n form: Pick<AvailabilityInput, \"responseCap\" | \"completedResponses\" | \"full\">,\n): boolean {\n if (form.full !== undefined) return form.full;\n return (\n form.responseCap != null &&\n form.completedResponses != null &&\n form.completedResponses >= form.responseCap\n );\n}\n\n// A date, a time, then Z or an hours-and-minutes offset.\nconst INSTANT = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\n/** An ISO time with `Z` or an offset, as epoch milliseconds; NaN for anything else. */\nexport function parseInstant(value: string): number {\n const v = value.trim();\n return INSTANT.test(v) ? Date.parse(v.replace(\" \", \"T\")) : Number.NaN;\n}\n\n/**\n * Where a form stands at `at`. Archived and draft first, then paused (staff chose it,\n * whatever the clock says), then the opening window (a time that can't be read, or has no\n * offset, counts as closed), then the cap. Only \"live\" takes\n * responses.\n */\nexport function formAvailability(form: AvailabilityInput, at: Date = new Date()): FormAvailability {\n if (form.status === \"archived\") return \"archived\";\n if (form.status === \"draft\" || form.published === false) return \"draft\";\n if (form.paused) return \"paused\";\n const t = at.getTime();\n if (form.opensAt) {\n const opens = parseInstant(form.opensAt);\n // A time that can't be read never opens the form.\n if (Number.isNaN(opens)) return \"closed\";\n if (t < opens) return \"scheduled\";\n }\n if (form.closesAt) {\n const closes = parseInstant(form.closesAt);\n if (Number.isNaN(closes) || t >= closes) return \"closed\";\n }\n if (isFull(form)) return \"full\";\n return \"live\";\n}\n\n/** Whether the form takes responses at `at`. */\nexport function takesResponses(form: AvailabilityInput, at: Date = new Date()): boolean {\n return formAvailability(form, at) === \"live\";\n}\n","// A form page's status chip and its four child navigation items with their counts. Pure.\nimport type { FormDefinition } from \"@marktiderman/genesis-forms\";\nimport type { FormAvailability } from \"./availability\";\nimport type { SubNavItem } from \"@marktiderman/genesis-ui/layout\";\nimport type { ChipTone } from \"@marktiderman/genesis-ui/resource/rules\";\n\n/**\n * A form's status chip: \"Live · version 3\", \"Draft\", \"Paused · version 3\"… `availability`\n * is formAvailability's answer; `version` the live version, when there is one.\n */\nexport function formStatusChip(\n availability: FormAvailability,\n version?: number | null,\n): { label: string; tone: ChipTone } {\n const v = version ? ` · version ${version}` : \"\";\n switch (availability) {\n case \"live\":\n return { label: `Live${v}`, tone: \"success\" };\n case \"draft\":\n return { label: \"Draft\", tone: \"muted\" };\n case \"paused\":\n return { label: `Paused${v}`, tone: \"warning\" };\n case \"scheduled\":\n return { label: `Scheduled${v}`, tone: \"info\" };\n case \"closed\":\n return { label: `Closed${v}`, tone: \"muted\" };\n case \"full\":\n return { label: `Full${v}`, tone: \"warning\" };\n case \"archived\":\n return { label: \"Archived\", tone: \"muted\" };\n }\n}\n\n/** The form page's four places, in order. */\nexport type FormTab = \"questions\" | \"logic\" | \"responses\" | \"settings\";\n\n/** One of a form page's child navigation items: genesis-ui's `SubNavItem`, plus its place. */\nexport type FormNavItem = SubNavItem & { id: FormTab; badge?: number };\n\n/** How many questions a definition asks, and how many rules plus endings it has. */\nexport function formCounts(definition: FormDefinition | null | undefined): {\n questions: number;\n logic: number;\n} {\n if (!definition) return { questions: 0, logic: 0 };\n return {\n questions: definition.blocks.filter((b) => b.kind === \"field\").length,\n logic: (definition.logic?.length ?? 0) + (definition.endings?.length ?? 0),\n };\n}\n\n/**\n * The form page's child navigation items (Questions, Logic and endings, Responses,\n * Settings) with their counts as badges, for the app shell's sub-navigation:\n * `useAppShellSubNav(formNavItems(\"/forms/f1\", counts))`. `at` is the form page's path\n * (each place is `?tab=<id>` on it, Questions the path itself, which the shell's most\n * specific match keeps from lighting up on the others) or a function giving each place's\n * address. A count left out (or null) shows no badge.\n */\nexport function formNavItems(\n at: string | ((tab: FormTab) => string),\n counts: { questions?: number | null; logic?: number | null; responses?: number | null } = {},\n /** Each place's icon, for the rail and the phone's bottom bar (`FORM_NAV_ICONS`). */\n icons?: Partial<Record<FormTab, SubNavItem[\"icon\"]>>,\n): FormNavItem[] {\n const to = typeof at === \"function\" ? at : (tab: FormTab) => (tab === \"questions\" ? at : `${at}?tab=${tab}`);\n const item = (id: FormTab, label: string, badge?: number | null): FormNavItem => {\n const icon = icons?.[id];\n return {\n id,\n to: to(id),\n label,\n ...(badge == null ? {} : { badge }),\n ...(icon ? { icon } : {}),\n };\n };\n return [\n item(\"questions\", \"Questions\", counts.questions),\n item(\"logic\", \"Logic and endings\", counts.logic),\n item(\"responses\", \"Responses\", counts.responses),\n item(\"settings\", \"Settings\"),\n ];\n}\n","// The pure half of the resource workspace moved to genesis-ui\n// (`@marktiderman/genesis-ui/resource/rules`). These names stay here, deprecated, so\n// existing imports keep working; the form's own words (an empty form says \"Add a\n// question\") are passed from here.\nimport {\n SAVE_STATE_LABEL as UI_SAVE_STATE_LABEL,\n dayLabel as uiDayLabel,\n embedSnippet as uiEmbedSnippet,\n prefilledUrl as uiPrefilledUrl,\n readinessChip as uiReadinessChip,\n readinessOf as uiReadinessOf,\n type ChipTone as UiChipTone,\n type PrefillChoice as UiPrefillChoice,\n type Readiness as UiReadiness,\n type ReadinessFinding,\n type ReadinessLabels,\n type ReadinessOptions,\n type SaveState as UiSaveState,\n} from \"@marktiderman/genesis-ui/resource/rules\";\n\n/** A form's readiness rule: the builder's `no-questions` finding means \"nothing to publish yet\". */\nexport const FORM_READINESS_OPTIONS = { emptyCode: \"no-questions\" } as const satisfies ReadinessOptions;\n\n/** A form's readiness words: an empty form says \"Add a question\". */\nexport const FORM_READINESS_LABELS = { empty: \"Add a question\" } as const satisfies ReadinessLabels;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type SaveState = UiSaveState;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type ChipTone = UiChipTone;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type Readiness = UiReadiness;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type PrefillChoice = UiPrefillChoice;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const SAVE_STATE_LABEL: Record<SaveState, string> = UI_SAVE_STATE_LABEL;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const dayLabel: typeof uiDayLabel = uiDayLabel;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const prefilledUrl: typeof uiPrefilledUrl = uiPrefilledUrl;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const embedSnippet: typeof uiEmbedSnippet = uiEmbedSnippet;\n\n/**\n * Readiness from a form builder's findings (`no-questions` is \"empty\").\n * @deprecated import from @marktiderman/genesis-ui: `readinessOf(findings, { ...FORM_READINESS_OPTIONS, pending })`\n */\nexport function readinessOf(\n findings: readonly ReadinessFinding[],\n options: ReadinessOptions = {},\n): Readiness {\n return uiReadinessOf(findings, { ...FORM_READINESS_OPTIONS, ...options });\n}\n\n/**\n * The readiness chip's label and tone, in a form's words.\n * @deprecated import from @marktiderman/genesis-ui: `readinessChip(readiness, FORM_READINESS_LABELS)`\n */\nexport function readinessChip(\n readiness: Readiness,\n labels: ReadinessLabels = {},\n): { label: string; tone: ChipTone } {\n return uiReadinessChip(readiness, { ...FORM_READINESS_LABELS, ...labels });\n}\n","// A form's public link and a duplicate's name: what a forms list needs to make a form or\n// copy one, without storage. Pure. Moved up from the host app's src/lib/feedback/admin.ts.\n\n/**\n * \"How was class?\" → \"how-was-class\": the public link's last part (lowercase words and\n * hyphens, at most 60). `fallback` is used when the title has no letters or numbers.\n */\nexport function slugFromTitle(title: string, fallback = \"form\"): string {\n const slug = title\n .toLowerCase()\n .normalize(\"NFKD\")\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60)\n .replace(/-+$/g, \"\");\n return slug || fallback;\n}\n\n/** A form link: lowercase letters and numbers, in words joined by single hyphens. */\nexport const SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;\n\n/** Why a form link can't be used, or nothing when it fits SLUG_PATTERN. */\nexport function validateSlug(slug: string): string | undefined {\n return SLUG_PATTERN.test(slug)\n ? undefined\n : \"Use lowercase letters, numbers and hyphens for the link, like how-was-class.\";\n}\n\n/** A duplicate's name: \"Copy of …\", within the 120 characters a form name may have. */\nexport function copyTitle(title: string): string {\n return `Copy of ${title}`.slice(0, 120);\n}\n\n/** The first of `slug`, `slug-2`, `slug-3`… that isn't in `taken`, within 60 characters. */\nexport function freeSlug(slug: string, taken: ReadonlySet<string>): string {\n if (!taken.has(slug)) return slug;\n for (let n = 2; ; n++) {\n const suffix = `-${n}`;\n const candidate = `${slug.slice(0, 60 - suffix.length).replace(/-+$/, \"\")}${suffix}`;\n if (!taken.has(candidate)) return candidate;\n }\n}\n","// What a respondent's thank-you page offers. Pure: safe in the browser bundle and in\n// tests. Moved up from the host app's src/lib/feedback/respondent.ts.\n\n/**\n * Whether the thank-you page offers \"Send another response\" (on unless `submitAnother`\n * is false). Never on a form that takes one response per person: a second response\n * would be refused. Anonymous forms don't know who answered, so one per person doesn't apply.\n */\nexport function offersSubmitAnother(form: {\n submitAnother?: boolean | null | undefined;\n onePerPerson?: boolean | null | undefined;\n anonymous?: boolean | null | undefined;\n}): boolean {\n const onePerPerson = form.onePerPerson === true && !form.anonymous;\n return form.submitAnother !== false && !onePerPerson;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ declare const FORM_NAV_ICONS: {
|
|
|
59
59
|
settings: react.ForwardRefExoticComponent<Omit<lucide_react.LucideProps, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
/** One "pick a value" filter over an extra column, such as a
|
|
62
|
+
/** One "pick a value" filter over an extra column, such as a location or a staff member. */
|
|
63
63
|
interface ChoiceFilter {
|
|
64
64
|
key: string;
|
|
65
65
|
/** "Any class": what the menu says when nothing is picked. */
|
|
@@ -67,7 +67,7 @@ interface ChoiceFilter {
|
|
|
67
67
|
/** For screen readers: "Class". */
|
|
68
68
|
label: string;
|
|
69
69
|
options: string[];
|
|
70
|
-
/** Shown before the value, e.g. a person icon for a
|
|
70
|
+
/** Shown before the value, e.g. a person icon for a staff member. */
|
|
71
71
|
icon?: ReactNode;
|
|
72
72
|
}
|
|
73
73
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { FORM_READINESS_LABELS, STATUS_FILTER_LABEL, lowThisWeek, NO_FILTERS, lowScaleAtMost } from './chunk-
|
|
3
|
-
export { FORM_READINESS_LABELS, FORM_READINESS_OPTIONS, NO_FILTERS, RESPONSE_STATUS_LABEL, SAVE_STATE_LABEL, SLUG_PATTERN, STATUS_FILTER_LABEL, answerCell, answerColumns, answersByKey, carryAnswers, comparisonFilter, copyTitle, dayLabel, dropOffByQuestion, dropOffSummary, embedSnippet, filterResponses, followUpOf, formAvailability, formCounts, formNavItems, formStatusChip, freeSlug, hasLowRating, hasLowRatingExcept, headlineCards, headlineNumbers, highestRating, isFiltered, isFull, lowRatingAtMost, lowRatingLabel, lowScaleAtMost, lowThisWeek, lowestRating, matchesStatus, needsFollowUp, offersSubmitAnother, parseInstant, plainLabel, prefilledUrl, presetRange, readinessChip, readinessOf, slugFromTitle, summarizeResponses, takesResponses, toCsv, toResponseFilter, validateSlug, valuesByKey } from './chunk-
|
|
2
|
+
import { FORM_READINESS_LABELS, STATUS_FILTER_LABEL, lowThisWeek, NO_FILTERS, lowScaleAtMost } from './chunk-NQYZ7PHD.js';
|
|
3
|
+
export { FORM_READINESS_LABELS, FORM_READINESS_OPTIONS, NO_FILTERS, RESPONSE_STATUS_LABEL, SAVE_STATE_LABEL, SLUG_PATTERN, STATUS_FILTER_LABEL, answerCell, answerColumns, answersByKey, carryAnswers, comparisonFilter, copyTitle, dayLabel, dropOffByQuestion, dropOffSummary, embedSnippet, filterResponses, followUpOf, formAvailability, formCounts, formNavItems, formStatusChip, freeSlug, hasLowRating, hasLowRatingExcept, headlineCards, headlineNumbers, highestRating, isFiltered, isFull, lowRatingAtMost, lowRatingLabel, lowScaleAtMost, lowThisWeek, lowestRating, matchesStatus, needsFollowUp, offersSubmitAnother, parseInstant, plainLabel, prefilledUrl, presetRange, readinessChip, readinessOf, slugFromTitle, summarizeResponses, takesResponses, toCsv, toResponseFilter, validateSlug, valuesByKey } from './chunk-NQYZ7PHD.js';
|
|
4
4
|
import { Chip as Chip$1, FollowUpList as FollowUpList$1, HeadlineNumbers as HeadlineNumbers$1, ResourceHeader as ResourceHeader$1, ResourceSettingsPage as ResourceSettingsPage$1, ResponsesToolbar as ResponsesToolbar$1, SettingsSection as SettingsSection$1, SummaryCard as SummaryCard$1, ReadinessChip as ReadinessChip$1, ShareDialog as ShareDialog$1, dayLabel } from '@marktiderman/genesis-ui/resource';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { Settings, Inbox, GitBranch, ListChecks, CalendarDays, CircleDashed, TriangleAlert, X, CircleDot, CircleCheck, SquareCheck, Gauge, Star, Type, ChartNoAxesColumnDecreasing, ImageOff, Image, ExternalLink } from 'lucide-react';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/moved.tsx","../src/navIcons.ts","../src/ResponsesFilters.tsx","../src/QuestionSummaryCards.tsx","../src/DropOffByQuestion.tsx","../src/PhotoAnswer.tsx"],"names":["UiResourceHeader","UiChip","UiResponsesToolbar","UiHeadlineNumbers","UiSummaryCard","UiFollowUpList","UiSettingsSection","UiResourceSettingsPage","UiReadinessChip","UiShareDialog","jsx","ListChecks","jsxs","dayLabel","Button","SummaryCard","Inbox","plural","Skeleton","cn","useState","ImageIcon"],"mappings":"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","file":"index.js","sourcesContent":["// The resource workspace's components moved to genesis-ui\n// (`@marktiderman/genesis-ui/resource`). These names stay here, deprecated, so existing\n// imports keep working; where genesis-ui's default words are neutral (\"Share your page\"),\n// the form's words are passed from here, so nothing a form shows changes.\nimport type { ComponentProps } from \"react\";\nimport {\n Chip as UiChip,\n FollowUpList as UiFollowUpList,\n HeadlineNumbers as UiHeadlineNumbers,\n ReadinessChip as UiReadinessChip,\n ResourceHeader as UiResourceHeader,\n ResourceSettingsPage as UiResourceSettingsPage,\n ResponsesToolbar as UiResponsesToolbar,\n SettingsSection as UiSettingsSection,\n ShareDialog as UiShareDialog,\n SummaryCard as UiSummaryCard,\n type FollowUpEntry as UiFollowUpEntry,\n type HeadlineNumber as UiHeadlineNumber,\n type ResourceHeaderProps as UiResourceHeaderProps,\n type ResourceSettingsSection,\n type ResponsesView as UiResponsesView,\n} from \"@marktiderman/genesis-ui/resource\";\nimport { FORM_READINESS_LABELS } from \"./moved-rules\";\n\n/** A form's Share dialog words: \"Share your form\", \"Anyone with the link can answer.\" */\nexport const FORM_SHARE_LABELS = {\n noun: \"form\",\n description: \"Anyone with the link can answer.\",\n} as const;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type ResourceHeaderProps = UiResourceHeaderProps;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type ResponsesView = UiResponsesView;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type HeadlineNumber = UiHeadlineNumber;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type FollowUpEntry = UiFollowUpEntry;\n/** @deprecated import `ResourceSettingsSection` from @marktiderman/genesis-ui */\nexport type SettingsPageSection = ResourceSettingsSection;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const ResourceHeader: typeof UiResourceHeader = UiResourceHeader;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const Chip: typeof UiChip = UiChip;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const ResponsesToolbar: typeof UiResponsesToolbar = UiResponsesToolbar;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const HeadlineNumbers: typeof UiHeadlineNumbers = UiHeadlineNumbers;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const SummaryCard: typeof UiSummaryCard = UiSummaryCard;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const FollowUpList: typeof UiFollowUpList = UiFollowUpList;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const SettingsSection: typeof UiSettingsSection = UiSettingsSection;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const ResourceSettingsPage: typeof UiResourceSettingsPage = UiResourceSettingsPage;\n\n/**\n * \"Ready to publish\", or how many problems to fix, in a form's words (\"Add a question\").\n * @deprecated import from @marktiderman/genesis-ui and pass `labels={FORM_READINESS_LABELS}`\n */\nexport function ReadinessChip({ labels, ...props }: ComponentProps<typeof UiReadinessChip>) {\n return <UiReadinessChip {...props} labels={{ ...FORM_READINESS_LABELS, ...labels }} />;\n}\n\n/**\n * Sharing a published form: \"Share your form\", \"Anyone with the link can answer.\"\n * @deprecated import from @marktiderman/genesis-ui and pass `{...FORM_SHARE_LABELS}`\n */\nexport function ShareDialog({\n noun = FORM_SHARE_LABELS.noun,\n description = FORM_SHARE_LABELS.description,\n ...props\n}: ComponentProps<typeof UiShareDialog>) {\n return <UiShareDialog {...props} noun={noun} description={description} />;\n}\n","import { GitBranch, Inbox, ListChecks, Settings } from \"lucide-react\";\nimport type { FormTab } from \"./status\";\n\n/** The form page's four places' icons, for `formNavItems(path, counts, FORM_NAV_ICONS)`. */\nexport const FORM_NAV_ICONS = {\n questions: ListChecks,\n logic: GitBranch,\n responses: Inbox,\n settings: Settings,\n} satisfies Record<FormTab, unknown>;\n","import type { ReactNode } from \"react\";\nimport {\n Button,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@marktiderman/genesis-ui\";\nimport { CalendarDays, CircleDashed, TriangleAlert, X } from \"lucide-react\";\nimport { lowThisWeek, NO_FILTERS, STATUS_FILTER_LABEL, type FiltersValue, type StatusFilter } from \"./summary\";\n\n/** One \"pick a value\" filter over an extra column, such as a class or a coach. */\nexport interface ChoiceFilter {\n key: string;\n /** \"Any class\": what the menu says when nothing is picked. */\n allLabel: string;\n /** For screen readers: \"Class\". */\n label: string;\n options: string[];\n /** Shown before the value, e.g. a person icon for a coach. */\n icon?: ReactNode;\n}\n\nconst WHEN: { value: FiltersValue[\"when\"]; label: string }[] = [\n { value: \"all\", label: \"All time\" },\n { value: \"today\", label: \"Today\" },\n { value: \"week\", label: \"This week\" },\n { value: \"7d\", label: \"Last 7 days\" },\n { value: \"30d\", label: \"Last 30 days\" },\n { value: \"month\", label: \"This month\" },\n { value: \"custom\", label: \"Pick dates\" },\n];\nconst ANY = \"__any\";\nconst TRIGGER = \"h-9 w-auto min-w-0 gap-2 [&>span]:flex [&>span]:items-center [&>span]:gap-2\";\n\n/**\n * Filters for a form's responses: when, the status (with `statuses`: Sent and partial,\n * Sent, Partial, In progress), any number of choice filters, a rating floor, and the\n * low-ratings chip (\"Low ratings this week\" until it's on; then a chip saying what low\n * means, with ×). The summary and the list of responses share one value.\n */\nexport function ResponsesFilters({\n value,\n onChange,\n choices = [],\n ratingMax = null,\n lowLabel = null,\n statuses = false,\n filtered,\n}: {\n /** Show the status filter: for a form that saves answers as they go (settings.saveProgress). */\n statuses?: boolean | undefined;\n value: FiltersValue;\n onChange: (next: FiltersValue) => void;\n choices?: readonly ChoiceFilter[] | undefined;\n /** The highest rating any question asks for (highestRating); no rating filter when null. */\n ratingMax?: number | null | undefined;\n /** What counts as low (lowRatingLabel); no low-ratings chip when null. */\n lowLabel?: string | null | undefined;\n /** Whether anything is left out (isFiltered), for Clear filters. */\n filtered: boolean;\n}) {\n const ratings = ratingMax ? Array.from({ length: Math.min(ratingMax, 10) - 1 }, (_, i) => i + 1) : [];\n return (\n <div className=\"flex flex-wrap items-center gap-2\" data-testid=\"responses-filters\">\n <Select value={value.when} onValueChange={(when) => onChange({ ...value, when: when as FiltersValue[\"when\"] })}>\n <SelectTrigger className={TRIGGER} aria-label=\"When\">\n <CalendarDays className=\"size-4 text-muted-foreground\" aria-hidden />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {WHEN.map((w) => (\n <SelectItem key={w.value} value={w.value}>\n {w.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {value.when === \"custom\" ? (\n <span className=\"flex items-center gap-1\">\n <Input\n type=\"date\"\n className=\"h-9 w-auto\"\n aria-label=\"From\"\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n />\n <span className=\"text-sm text-muted-foreground\">to</span>\n <Input\n type=\"date\"\n className=\"h-9 w-auto\"\n aria-label=\"To\"\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n />\n </span>\n ) : null}\n {statuses ? (\n <Select\n value={value.status ?? \"counted\"}\n onValueChange={(status) => onChange({ ...value, status: status as StatusFilter })}\n >\n <SelectTrigger className={TRIGGER} aria-label=\"Status\" data-testid=\"responses-status\">\n <CircleDashed className=\"size-4 text-muted-foreground\" aria-hidden />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(STATUS_FILTER_LABEL) as StatusFilter[]).map((s) => (\n <SelectItem key={s} value={s}>\n {STATUS_FILTER_LABEL[s]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n {choices\n .filter((c) => c.options.length > 0)\n .map((c) => (\n <Select\n key={c.key}\n value={value.match[c.key] || ANY}\n onValueChange={(v) => onChange({ ...value, match: { ...value.match, [c.key]: v === ANY ? \"\" : v } })}\n >\n <SelectTrigger className={`${TRIGGER} max-w-56`} aria-label={c.label}>\n {c.icon ? (\n <span className=\"text-muted-foreground [&_svg]:size-4\" aria-hidden>\n {c.icon}\n </span>\n ) : null}\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ANY}>{c.allLabel}</SelectItem>\n {c.options.map((o) => (\n <SelectItem key={o} value={o}>\n {o}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ))}\n {ratings.length > 0 ? (\n <Select\n value={value.ratingAtMost == null ? ANY : String(value.ratingAtMost)}\n onValueChange={(v) => onChange({ ...value, ratingAtMost: v === ANY ? null : Number(v) })}\n >\n <SelectTrigger className={TRIGGER} aria-label=\"Rating\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ANY}>Any rating</SelectItem>\n {ratings.map((r) => (\n <SelectItem key={r} value={String(r)}>\n {r === 1 ? \"Rated 1\" : `Rated ${r} or below`}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n {lowLabel ? (\n value.low ? (\n <span\n className=\"inline-flex h-9 items-center gap-1.5 rounded-md bg-warning/15 pl-2.5 pr-1 text-sm text-amber-800 dark:bg-warning/20 dark:text-amber-200\"\n data-testid=\"low-ratings-chip\"\n >\n <TriangleAlert className=\"size-4\" aria-hidden />\n {`Low ratings (${lowLabel})`}\n <button\n type=\"button\"\n aria-label=\"Show every rating\"\n className=\"rounded p-1 hover:bg-warning/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onClick={() => onChange({ ...value, low: false })}\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n </span>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-9\"\n startIcon={<TriangleAlert className=\"size-4\" />}\n onClick={() => onChange(lowThisWeek(value))}\n data-testid=\"low-ratings-preset\"\n >\n Low ratings this week\n </Button>\n )\n ) : null}\n {filtered ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-9\" onClick={() => onChange(NO_FILTERS)}>\n Clear filters\n </Button>\n ) : null}\n </div>\n );\n}\n","import { useState, type ComponentType, type ReactNode } from \"react\";\nimport { Button, EmptyState, Skeleton, cn } from \"@marktiderman/genesis-ui\";\nimport {\n CircleCheck,\n CircleDot,\n Gauge,\n Inbox,\n ListChecks,\n SquareCheck,\n Star,\n Type,\n type LucideProps,\n} from \"lucide-react\";\nimport { dayLabel, SummaryCard } from \"@marktiderman/genesis-ui/resource\";\nimport { lowScaleAtMost } from \"./summary\";\nimport type { ChoiceSummary, QuestionSummary, ScaleSummary, TextSummary } from \"./summary\";\n\nconst FIRST_TEXT = 5;\nconst MORE_TEXT = 10;\n\nconst plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;\n\nconst ICONS: Record<string, ComponentType<LucideProps>> = {\n rating: Star,\n nps: Gauge,\n consent: SquareCheck,\n \"yes-no\": CircleCheck,\n \"single-choice\": CircleDot,\n dropdown: CircleDot,\n \"multi-choice\": ListChecks,\n};\n\n/** A bar as wide as its share; low scores in the warning colour. */\nfunction Bar({ share, low = false }: { share: number; low?: boolean }) {\n return (\n <span className=\"h-2 overflow-hidden rounded-full bg-muted\" aria-hidden>\n <span\n className={cn(\"block h-full rounded-full\", low ? \"bg-warning\" : \"bg-primary\")}\n style={{ width: `${Math.max(0, Math.min(100, share))}%` }}\n />\n </span>\n );\n}\n\nfunction ScaleBody({ s }: { s: ScaleSummary }) {\n const most = Math.max(1, ...s.buckets.map((b) => b.count));\n const atMost = lowScaleAtMost(s.type, s.max);\n return (\n <>\n {s.nps ? (\n <p className=\"text-sm\">\n <span className=\"text-2xl font-semibold tabular-nums\">{s.nps.score}</span>{\" \"}\n <span className=\"text-muted-foreground\">NPS</span>\n <span className=\"block text-xs text-muted-foreground\">\n {plural(s.nps.promoters, \"promoter\")} (9–10), {plural(s.nps.passives, \"passive\")} (7–8),{\" \"}\n {plural(s.nps.detractors, \"detractor\")} (0–6)\n </span>\n </p>\n ) : null}\n {s.rescaled || s.excluded ? (\n <p className=\"text-xs text-muted-foreground\" data-testid={`scale-note-${s.key}`}>\n {[\n s.rescaled\n ? `${plural(s.rescaled, \"answer\")} from an earlier version's scale moved onto ${s.min}–${s.max}.`\n : \"\",\n s.excluded ? `${plural(s.excluded, \"answer\")} outside the scale left out.` : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n </p>\n ) : null}\n <ul className=\"space-y-2\" aria-label=\"Answers by score\">\n {[...s.buckets].reverse().map((b) => (\n <li key={b.value} className=\"grid grid-cols-[2.25rem_1fr_2rem] items-center gap-3 text-sm\">\n <span className=\"flex items-center gap-1 tabular-nums\">\n {b.value}\n {s.type === \"rating\" ? <Star className=\"size-3 fill-current\" aria-label=\"stars\" /> : null}\n </span>\n <Bar share={(b.count / most) * 100} low={b.value <= atMost} />\n <span className=\"text-right tabular-nums text-muted-foreground\">{b.count}</span>\n </li>\n ))}\n </ul>\n </>\n );\n}\n\n/** Two-way questions (consent, yes/no) as one split bar; others as a bar per option. */\nfunction ChoiceBody({ s }: { s: ChoiceSummary }) {\n if (s.fieldType === \"consent\" || s.fieldType === \"yes-no\") {\n const yes = s.options.find((o) => o.value === \"true\");\n const no = s.options.find((o) => o.value === \"false\");\n return (\n <>\n <span className=\"flex h-2.5 overflow-hidden rounded-full bg-muted\" aria-hidden>\n <span className=\"h-full bg-primary\" style={{ width: `${yes?.percent ?? 0}%` }} />\n </span>\n <p className=\"flex flex-wrap gap-x-4 gap-y-1 text-sm\">\n {yes ? (\n <span className=\"text-emerald-700 dark:text-emerald-300\">\n {yes.label} · {yes.count} ({Math.round(yes.percent)}%)\n </span>\n ) : null}\n {no ? (\n <span className=\"text-muted-foreground\">\n {no.label} · {no.count}\n </span>\n ) : null}\n </p>\n </>\n );\n }\n const most = Math.max(1, ...s.options.map((o) => o.count));\n return (\n <>\n <ul className=\"space-y-2\">\n {s.options.map((o) => (\n <li key={o.value} className=\"grid grid-cols-[minmax(2rem,12rem)_1fr_auto] items-center gap-3 text-sm\">\n <span className=\"truncate\" title={o.label}>\n {o.label}\n </span>\n <Bar share={(o.count / most) * 100} />\n <span className=\"whitespace-nowrap text-right tabular-nums text-muted-foreground\">\n {o.count} · {Math.round(o.percent)}%\n </span>\n </li>\n ))}\n </ul>\n {s.multiple ? <p className=\"text-xs text-muted-foreground\">People could pick more than one.</p> : null}\n </>\n );\n}\n\nfunction TextBody({\n s,\n today,\n answerMeta,\n}: {\n s: TextSummary;\n today?: string | undefined;\n answerMeta?: ((id: string) => ReactNode) | undefined;\n}) {\n const [shown, setShown] = useState(FIRST_TEXT);\n const left = s.answers.length - shown;\n return (\n <>\n <ul className=\"space-y-3\">\n {s.answers.slice(0, shown).map((a) => {\n const meta = answerMeta?.(a.id);\n return (\n <li key={a.id} className=\"border-l-2 border-border pl-3\">\n <p className=\"whitespace-pre-wrap break-words text-sm\">“{a.text}”</p>\n <p className=\"text-xs text-muted-foreground\">\n {dayLabel(a.date, today)}\n {meta ? <> · {meta}</> : null}\n </p>\n </li>\n );\n })}\n </ul>\n {left > 0 ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"self-start\" onClick={() => setShown((n) => n + MORE_TEXT)}>\n Show more ({left} more)\n </Button>\n ) : null}\n </>\n );\n}\n\n/** One question's card: its type icon, title and answer count, then its spread. */\nexport function QuestionSummaryCard({\n summary: s,\n today,\n answerMeta,\n}: {\n summary: QuestionSummary;\n today?: string | undefined;\n answerMeta?: ((id: string) => ReactNode) | undefined;\n}) {\n const Icon = ICONS[s.fieldType] ?? Type;\n const average = s.kind === \"scale\" && s.average !== null ? ` · average ${s.average.toFixed(1)}` : \"\";\n return (\n <SummaryCard\n icon={<Icon />}\n title={s.label || \"Untitled question\"}\n meta={s.count ? `${plural(s.count, \"answer\")}${average}` : \"No answers yet\"}\n testID={`summary-${s.key}`}\n >\n {s.count > 0 ? (\n s.kind === \"scale\" ? (\n <ScaleBody s={s} />\n ) : s.kind === \"choice\" ? (\n <ChoiceBody s={s} />\n ) : (\n <TextBody s={s} today={today} answerMeta={answerMeta} />\n )\n ) : null}\n </SummaryCard>\n );\n}\n\n/**\n * A form's responses question by question (summarizeResponses): each rating or NPS\n * question's spread with low scores marked, counts for each choice, consent and yes/no\n * as one split bar, and the latest written answers.\n */\nexport function QuestionSummaryCards({\n summaries,\n responses,\n isLoading = false,\n emptyTitle = \"No responses yet\",\n emptyDescription,\n onClearFilters,\n today,\n answerMeta,\n className,\n}: {\n summaries: readonly QuestionSummary[];\n /** How many responses the summaries cover. */\n responses: number;\n isLoading?: boolean | undefined;\n emptyTitle?: string | undefined;\n emptyDescription?: string | undefined;\n /** Given while filters are on: an empty summary then says so, with a way out. */\n onClearFilters?: (() => void) | undefined;\n /** Today (YYYY-MM-DD) on the responses' clock, so written answers say \"Today\". */\n today?: string | undefined;\n /** Extra words after a written answer's day, by response id: \"6:00 WOD · rated 2\". */\n answerMeta?: ((id: string) => ReactNode) | undefined;\n className?: string | undefined;\n}) {\n if (isLoading) {\n return (\n <div className={cn(\"space-y-3\", className)}>\n <Skeleton className=\"h-40 w-full rounded-lg\" />\n <Skeleton className=\"h-32 w-full rounded-lg\" />\n </div>\n );\n }\n if (!responses) {\n return (\n <EmptyState\n icon={Inbox}\n title={emptyTitle}\n {...(emptyDescription ? { description: emptyDescription } : {})}\n hasFilters={!!onClearFilters}\n {...(onClearFilters ? { onClearFilters } : {})}\n />\n );\n }\n return (\n <div className={cn(\"flex min-w-0 flex-col gap-3\", className)}>\n {summaries.map((s) => (\n <QuestionSummaryCard key={s.key} summary={s} today={today} answerMeta={answerMeta} />\n ))}\n </div>\n );\n}\n","import { Skeleton, cn } from \"@marktiderman/genesis-ui\";\nimport { ChartNoAxesColumnDecreasing } from \"lucide-react\";\nimport { SummaryCard } from \"@marktiderman/genesis-ui/resource\";\nimport type { QuestionDropOff } from \"./dropoff\";\n\nconst plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;\n\n/**\n * Drop-off by question (`dropOffSummary`): how many people started, then for each question in\n * order how many reached it, how many stopped there, and that as a share, with the share as\n * a bar (the question most people left on in the warning colour). For a form that saves\n * answers as they go. Spread `dropOffSummary(...)` into it; without `started` it falls back\n * to the first question's views, which leaves out responses in progress and anyone logic\n * hid the first question from.\n */\nexport function DropOffByQuestion({\n dropOffs,\n started: startedCount,\n isLoading = false,\n title = \"Drop-off by question\",\n className,\n}: {\n dropOffs: readonly QuestionDropOff[];\n /** How many people started (`dropOffSummary`'s `started`). */\n started?: number | undefined;\n isLoading?: boolean | undefined;\n title?: string | undefined;\n className?: string | undefined;\n}) {\n if (isLoading) return <Skeleton className={cn(\"h-40 w-full rounded-lg\", className)} />;\n const started = startedCount ?? dropOffs[0]?.views ?? 0;\n const worst = Math.max(0, ...dropOffs.map((d) => d.stopped));\n return (\n <SummaryCard\n icon={<ChartNoAxesColumnDecreasing />}\n title={title}\n meta={started ? `${plural(started, \"person\", \"people\")} started` : \"Nobody has started yet\"}\n className={className}\n testID=\"drop-off\"\n >\n {started ? (\n <ol className=\"space-y-3\">\n {dropOffs.map((d, i) => (\n <li key={d.key} className=\"space-y-1.5 text-sm\" data-testid={`drop-off-${d.key}`}>\n <p className=\"flex items-baseline justify-between gap-3\">\n <span className=\"min-w-0 break-words\">\n <span className=\"text-muted-foreground tabular-nums\">{i + 1}. </span>\n {d.label || \"Untitled question\"}\n </span>\n <span className=\"shrink-0 whitespace-nowrap tabular-nums text-muted-foreground\">\n {d.dropOff === null ? \"–\" : `${d.dropOff}% drop-off`}\n </span>\n </p>\n <span className=\"block h-2 overflow-hidden rounded-full bg-muted\" aria-hidden>\n <span\n className={cn(\n \"block h-full rounded-full\",\n d.stopped && d.stopped === worst ? \"bg-warning\" : \"bg-primary\",\n )}\n style={{ width: `${d.dropOff ?? 0}%` }}\n />\n </span>\n <p className=\"text-xs text-muted-foreground\">\n {plural(d.views, \"view\")} · {d.stopped} stopped here\n </p>\n </li>\n ))}\n </ol>\n ) : null}\n </SummaryCard>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { ExternalLink, ImageOff, Image as ImageIcon } from \"lucide-react\";\nimport { cn, Skeleton } from \"@marktiderman/genesis-ui\";\nimport type { PhotoRef } from \"@marktiderman/genesis-forms\";\n\n/** Types most browsers can't draw (HEIC and HEIF): shown as a file tile with an Open link. */\nconst UNDRAWABLE = new Set([\"image/heic\", \"image/heif\"]);\n\ntype Resolved = { state: \"loading\" } | { state: \"ready\"; url: string } | { state: \"missing\" };\n\nfunction Photo({ photo, resolveUrl }: { photo: PhotoRef; resolveUrl: (ref: PhotoRef) => Promise<string | null> }) {\n const [resolved, setResolved] = useState<Resolved>({ state: \"loading\" });\n const [broken, setBroken] = useState(false);\n\n // Each photo's address is asked for once (per photo id); a signed link may expire, so\n // it isn't kept beyond this view.\n useEffect(() => {\n let live = true;\n setResolved({ state: \"loading\" });\n setBroken(false);\n resolveUrl(photo)\n .then((url) => live && setResolved(url ? { state: \"ready\", url } : { state: \"missing\" }))\n .catch(() => live && setResolved({ state: \"missing\" }));\n return () => {\n live = false;\n };\n }, [photo.id]); // eslint-disable-line react-hooks/exhaustive-deps -- resolveUrl is often an inline function\n\n const tile = \"relative size-28 overflow-hidden rounded-md border border-border bg-muted\";\n if (resolved.state === \"loading\") return <Skeleton className=\"size-28 rounded-md\" aria-label={`Loading ${photo.name}`} />;\n if (resolved.state === \"missing\") {\n return (\n <div className={cn(tile, \"flex flex-col items-center justify-center gap-1 p-2 text-center text-xs text-muted-foreground\")}>\n <ImageOff className=\"size-5\" aria-hidden=\"true\" />\n <span>Photo unavailable</span>\n </div>\n );\n }\n if (broken || UNDRAWABLE.has(photo.type.toLowerCase())) {\n return (\n <div className={cn(tile, \"flex flex-col items-center justify-center gap-1 p-2 text-center text-xs\")}>\n <ImageIcon className=\"size-5 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"line-clamp-2 break-all text-muted-foreground\">{photo.name}</span>\n <a\n href={resolved.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 font-medium text-primary underline-offset-4 hover:underline\"\n >\n Open <ExternalLink className=\"size-3\" aria-hidden=\"true\" />\n <span className=\"sr-only\">{photo.name}</span>\n </a>\n </div>\n );\n }\n return (\n <a\n href={resolved.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={cn(tile, \"block outline-none ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\")}\n title={photo.name}\n >\n <img src={resolved.url} alt={photo.name} loading=\"lazy\" className=\"size-full object-cover\" onError={() => setBroken(true)} />\n </a>\n );\n}\n\n/**\n * A response's photos as thumbnails, each opening full size in a new tab. Data-agnostic:\n * the host resolves each reference to an address it may show (a short-lived signed link,\n * say), or null when it can't. A photo most browsers can't draw (HEIC) is a tile with\n * its name and an Open link; one that can't be found says so.\n */\nexport function PhotoAnswer({\n photos,\n resolveUrl,\n className,\n testID,\n}: {\n photos: PhotoRef[];\n resolveUrl: (ref: PhotoRef) => Promise<string | null>;\n className?: string | undefined;\n testID?: string | undefined;\n}) {\n if (!photos.length) return null;\n return (\n <ul className={cn(\"flex flex-wrap gap-3\", className)} aria-label=\"Photos\" data-testid={testID}>\n {photos.map((photo) => (\n <li key={photo.id}>\n <Photo photo={photo} resolveUrl={resolveUrl} />\n </li>\n ))}\n </ul>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/moved.tsx","../src/navIcons.ts","../src/ResponsesFilters.tsx","../src/QuestionSummaryCards.tsx","../src/DropOffByQuestion.tsx","../src/PhotoAnswer.tsx"],"names":["UiResourceHeader","UiChip","UiResponsesToolbar","UiHeadlineNumbers","UiSummaryCard","UiFollowUpList","UiSettingsSection","UiResourceSettingsPage","UiReadinessChip","UiShareDialog","jsx","ListChecks","jsxs","dayLabel","Button","SummaryCard","Inbox","plural","Skeleton","cn","useState","ImageIcon"],"mappings":";;;;;;;;;AAyBO,IAAM,iBAAA,GAAoB;AAAA,EAC/B,IAAA,EAAM,MAAA;AAAA,EACN,WAAA,EAAa;AACf;AAcO,IAAM,cAAA,GAA0CA;AAEhD,IAAM,IAAA,GAAsBC;AAE5B,IAAM,gBAAA,GAA8CC;AAEpD,IAAM,eAAA,GAA4CC;AAElD,IAAM,WAAA,GAAoCC;AAE1C,IAAM,YAAA,GAAsCC;AAE5C,IAAM,eAAA,GAA4CC;AAElD,IAAM,oBAAA,GAAsDC;AAM5D,SAAS,aAAA,CAAc,EAAE,MAAA,EAAQ,GAAG,OAAM,EAA2C;AAC1F,EAAA,uBAAO,GAAA,CAACC,eAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,MAAA,EAAQ,EAAE,GAAG,qBAAA,EAAuB,GAAG,MAAA,EAAO,EAAG,CAAA;AACtF;AAMO,SAAS,WAAA,CAAY;AAAA,EAC1B,OAAO,iBAAA,CAAkB,IAAA;AAAA,EACzB,cAAc,iBAAA,CAAkB,WAAA;AAAA,EAChC,GAAG;AACL,CAAA,EAAyC;AACvC,EAAA,uBAAO,GAAA,CAACC,aAAA,EAAA,EAAe,GAAG,KAAA,EAAO,MAAY,WAAA,EAA0B,CAAA;AACzE;ACxEO,IAAM,cAAA,GAAiB;AAAA,EAC5B,SAAA,EAAW,UAAA;AAAA,EACX,KAAA,EAAO,SAAA;AAAA,EACP,SAAA,EAAW,KAAA;AAAA,EACX,QAAA,EAAU;AACZ;ACgBA,IAAM,IAAA,GAAyD;AAAA,EAC7D,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,UAAA,EAAW;AAAA,EAClC,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,OAAA,EAAQ;AAAA,EACjC,EAAE,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,WAAA,EAAY;AAAA,EACpC,EAAE,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,aAAA,EAAc;AAAA,EACpC,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,cAAA,EAAe;AAAA,EACtC,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,YAAA,EAAa;AAAA,EACtC,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,YAAA;AAC5B,CAAA;AACA,IAAM,GAAA,GAAM,OAAA;AACZ,IAAM,OAAA,GAAU,6EAAA;AAQT,SAAS,gBAAA,CAAiB;AAAA,EAC/B,KAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAU,EAAC;AAAA,EACX,SAAA,GAAY,IAAA;AAAA,EACZ,QAAA,GAAW,IAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX;AACF,CAAA,EAYG;AACD,EAAA,MAAM,UAAU,SAAA,GAAY,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,KAAK,GAAA,CAAI,SAAA,EAAW,EAAE,CAAA,GAAI,CAAA,IAAK,CAAC,CAAA,EAAG,MAAM,CAAA,GAAI,CAAC,IAAI,EAAC;AACpG,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mCAAA,EAAoC,eAAY,mBAAA,EAC7D,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,MAAA,EAAA,EAAO,KAAA,EAAO,KAAA,CAAM,IAAA,EAAM,aAAA,EAAe,CAAC,IAAA,KAAS,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,IAAA,EAAoC,CAAA,EAC3G,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,aAAA,EAAA,EAAc,SAAA,EAAW,OAAA,EAAS,YAAA,EAAW,MAAA,EAC5C,QAAA,EAAA;AAAA,wBAAAC,GAAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAU,8BAAA,EAA+B,eAAW,IAAA,EAAC,CAAA;AAAA,wBACnEA,IAAC,WAAA,EAAA,EAAY;AAAA,OAAA,EACf,CAAA;AAAA,sBACAA,GAAAA,CAAC,aAAA,EAAA,EACE,eAAK,GAAA,CAAI,CAAC,sBACTA,GAAAA,CAAC,UAAA,EAAA,EAAyB,KAAA,EAAO,EAAE,KAAA,EAChC,QAAA,EAAA,CAAA,CAAE,SADY,CAAA,CAAE,KAEnB,CACD,CAAA,EACH;AAAA,KAAA,EACF,CAAA;AAAA,IACC,MAAM,IAAA,KAAS,QAAA,mBACd,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,yBAAA,EACd,QAAA,EAAA;AAAA,sBAAAA,GAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,MAAA;AAAA,UACL,SAAA,EAAU,YAAA;AAAA,UACV,YAAA,EAAW,MAAA;AAAA,UACX,OAAO,KAAA,CAAM,IAAA;AAAA,UACb,GAAA,EAAK,MAAM,EAAA,IAAM,MAAA;AAAA,UACjB,QAAA,EAAU,CAAC,CAAA,KAAM,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,CAAA,CAAE,MAAA,CAAO,KAAA,EAAO;AAAA;AAAA,OAC9D;AAAA,sBACAA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAgC,QAAA,EAAA,IAAA,EAAE,CAAA;AAAA,sBAClDA,GAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,MAAA;AAAA,UACL,SAAA,EAAU,YAAA;AAAA,UACV,YAAA,EAAW,IAAA;AAAA,UACX,OAAO,KAAA,CAAM,EAAA;AAAA,UACb,GAAA,EAAK,MAAM,IAAA,IAAQ,MAAA;AAAA,UACnB,QAAA,EAAU,CAAC,CAAA,KAAM,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,EAAA,EAAI,CAAA,CAAE,MAAA,CAAO,KAAA,EAAO;AAAA;AAAA;AAC5D,KAAA,EACF,CAAA,GACE,IAAA;AAAA,IACH,QAAA,mBACC,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,MAAM,MAAA,IAAU,SAAA;AAAA,QACvB,aAAA,EAAe,CAAC,MAAA,KAAW,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,QAAgC,CAAA;AAAA,QAEhF,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,iBAAc,SAAA,EAAW,OAAA,EAAS,YAAA,EAAW,QAAA,EAAS,eAAY,kBAAA,EACjE,QAAA,EAAA;AAAA,4BAAAA,GAAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAU,8BAAA,EAA+B,eAAW,IAAA,EAAC,CAAA;AAAA,4BACnEA,IAAC,WAAA,EAAA,EAAY;AAAA,WAAA,EACf,CAAA;AAAA,0BACAA,IAAC,aAAA,EAAA,EACG,QAAA,EAAA,MAAA,CAAO,KAAK,mBAAmB,CAAA,CAAqB,IAAI,CAAC,CAAA,qBACzDA,GAAAA,CAAC,UAAA,EAAA,EAAmB,OAAO,CAAA,EACxB,QAAA,EAAA,mBAAA,CAAoB,CAAC,CAAA,EAAA,EADP,CAEjB,CACD,CAAA,EACH;AAAA;AAAA;AAAA,KACF,GACE,IAAA;AAAA,IACH,OAAA,CACE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAA,CAClC,GAAA,CAAI,CAAC,CAAA,qBACJ,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,CAAA,CAAE,GAAG,CAAA,IAAK,GAAA;AAAA,QAC7B,aAAA,EAAe,CAAC,CAAA,KAAM,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,OAAO,EAAE,GAAG,MAAM,KAAA,EAAO,CAAC,EAAE,GAAG,GAAG,MAAM,GAAA,GAAM,EAAA,GAAK,CAAA,EAAE,EAAG,CAAA;AAAA,QAEnG,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,iBAAc,SAAA,EAAW,CAAA,EAAG,OAAO,CAAA,SAAA,CAAA,EAAa,YAAA,EAAY,EAAE,KAAA,EAC5D,QAAA,EAAA;AAAA,YAAA,CAAA,CAAE,IAAA,mBACDA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wCAAuC,aAAA,EAAW,IAAA,EAC/D,QAAA,EAAA,CAAA,CAAE,IAAA,EACL,CAAA,GACE,IAAA;AAAA,4BACJA,IAAC,WAAA,EAAA,EAAY;AAAA,WAAA,EACf,CAAA;AAAA,+BACC,aAAA,EAAA,EACC,QAAA,EAAA;AAAA,4BAAAA,GAAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAO,GAAA,EAAM,YAAE,QAAA,EAAS,CAAA;AAAA,YACnC,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,qBACdA,GAAAA,CAAC,UAAA,EAAA,EAAmB,KAAA,EAAO,CAAA,EACxB,QAAA,EAAA,CAAA,EAAA,EADc,CAEjB,CACD;AAAA,WAAA,EACH;AAAA;AAAA,OAAA;AAAA,MAnBK,CAAA,CAAE;AAAA,KAqBV,CAAA;AAAA,IACF,OAAA,CAAQ,SAAS,CAAA,mBAChB,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAO,KAAA,CAAM,YAAA,IAAgB,OAAO,GAAA,GAAM,MAAA,CAAO,MAAM,YAAY,CAAA;AAAA,QACnE,aAAA,EAAe,CAAC,CAAA,KAAM,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,YAAA,EAAc,CAAA,KAAM,GAAA,GAAM,IAAA,GAAO,MAAA,CAAO,CAAC,GAAG,CAAA;AAAA,QAEvF,QAAA,EAAA;AAAA,0BAAAA,GAAAA,CAAC,iBAAc,SAAA,EAAW,OAAA,EAAS,cAAW,QAAA,EAC5C,QAAA,kBAAAA,GAAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EACf,CAAA;AAAA,+BACC,aAAA,EAAA,EACC,QAAA,EAAA;AAAA,4BAAAA,GAAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAO,GAAA,EAAK,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,YACjC,QAAQ,GAAA,CAAI,CAAC,sBACZA,GAAAA,CAAC,cAAmB,KAAA,EAAO,MAAA,CAAO,CAAC,CAAA,EAChC,gBAAM,CAAA,GAAI,SAAA,GAAY,SAAS,CAAC,CAAA,SAAA,CAAA,EAAA,EADlB,CAEjB,CACD;AAAA,WAAA,EACH;AAAA;AAAA;AAAA,KACF,GACE,IAAA;AAAA,IACH,QAAA,GACC,MAAM,GAAA,mBACJ,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,yIAAA;AAAA,QACV,aAAA,EAAY,kBAAA;AAAA,QAEZ,QAAA,EAAA;AAAA,0BAAAA,GAAAA,CAAC,aAAA,EAAA,EAAc,SAAA,EAAU,QAAA,EAAS,eAAW,IAAA,EAAC,CAAA;AAAA,UAC7C,gBAAgB,QAAQ,CAAA,CAAA,CAAA;AAAA,0BACzBA,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,YAAA,EAAW,mBAAA;AAAA,cACX,SAAA,EAAU,yGAAA;AAAA,cACV,OAAA,EAAS,MAAM,QAAA,CAAS,EAAE,GAAG,KAAA,EAAO,GAAA,EAAK,OAAO,CAAA;AAAA,cAEhD,0BAAAA,GAAAA,CAAC,CAAA,EAAA,EAAE,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC;AAAA;AAAA;AACtC;AAAA;AAAA,wBAGFA,GAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,SAAA;AAAA,QACR,IAAA,EAAK,IAAA;AAAA,QACL,SAAA,EAAU,KAAA;AAAA,QACV,SAAA,kBAAWA,GAAAA,CAAC,aAAA,EAAA,EAAc,WAAU,QAAA,EAAS,CAAA;AAAA,QAC7C,OAAA,EAAS,MAAM,QAAA,CAAS,WAAA,CAAY,KAAK,CAAC,CAAA;AAAA,QAC1C,aAAA,EAAY,oBAAA;AAAA,QACb,QAAA,EAAA;AAAA;AAAA,KAED,GAEA,IAAA;AAAA,IACH,2BACCA,GAAAA,CAAC,MAAA,EAAA,EAAO,OAAA,EAAQ,SAAQ,IAAA,EAAK,IAAA,EAAK,SAAA,EAAU,KAAA,EAAM,SAAS,MAAM,QAAA,CAAS,UAAU,CAAA,EAAG,2BAEvF,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;ACvLA,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,SAAA,GAAY,EAAA;AAElB,IAAM,MAAA,GAAS,CAAC,CAAA,EAAW,GAAA,EAAa,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,CAAA,KAAQ,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAA,KAAM,CAAA,GAAI,MAAM,IAAI,CAAA,CAAA;AAEzF,IAAM,KAAA,GAAoD;AAAA,EACxD,MAAA,EAAQ,IAAA;AAAA,EACR,GAAA,EAAK,KAAA;AAAA,EACL,OAAA,EAAS,WAAA;AAAA,EACT,QAAA,EAAU,WAAA;AAAA,EACV,eAAA,EAAiB,SAAA;AAAA,EACjB,QAAA,EAAU,SAAA;AAAA,EACV,cAAA,EAAgBC;AAClB,CAAA;AAGA,SAAS,GAAA,CAAI,EAAE,KAAA,EAAO,GAAA,GAAM,OAAM,EAAqC;AACrE,EAAA,uBACED,GAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2CAAA,EAA4C,aAAA,EAAW,MACrE,QAAA,kBAAAA,GAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA,CAAG,2BAAA,EAA6B,GAAA,GAAM,eAAe,YAAY,CAAA;AAAA,MAC5E,KAAA,EAAO,EAAE,KAAA,EAAO,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAC,CAAA,CAAA,CAAA;AAAI;AAAA,GAC1D,EACF,CAAA;AAEJ;AAEA,SAAS,SAAA,CAAU,EAAE,CAAA,EAAE,EAAwB;AAC7C,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AACzD,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,CAAA,CAAE,IAAA,EAAM,EAAE,GAAG,CAAA;AAC3C,EAAA,uBACEE,KAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,CAAA,CAAE,GAAA,mBACDA,IAAAA,CAAC,GAAA,EAAA,EAAE,WAAU,SAAA,EACX,QAAA,EAAA;AAAA,sBAAAF,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qCAAA,EAAuC,QAAA,EAAA,CAAA,CAAE,IAAI,KAAA,EAAM,CAAA;AAAA,MAAQ,GAAA;AAAA,sBAC3EA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAwB,QAAA,EAAA,KAAA,EAAG,CAAA;AAAA,sBAC3CE,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qCAAA,EACb,QAAA,EAAA;AAAA,QAAA,MAAA,CAAO,CAAA,CAAE,GAAA,CAAI,SAAA,EAAW,UAAU,CAAA;AAAA,QAAE,gBAAA;AAAA,QAAU,MAAA,CAAO,CAAA,CAAE,GAAA,CAAI,QAAA,EAAU,SAAS,CAAA;AAAA,QAAE,cAAA;AAAA,QAAQ,GAAA;AAAA,QACxF,MAAA,CAAO,CAAA,CAAE,GAAA,CAAI,UAAA,EAAY,WAAW,CAAA;AAAA,QAAE;AAAA,OAAA,EACzC;AAAA,KAAA,EACF,CAAA,GACE,IAAA;AAAA,IACH,CAAA,CAAE,QAAA,IAAY,CAAA,CAAE,QAAA,mBACfF,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EAAgC,aAAA,EAAa,CAAA,WAAA,EAAc,CAAA,CAAE,GAAG,CAAA,CAAA,EAC1E,QAAA,EAAA;AAAA,MACC,CAAA,CAAE,QAAA,GACE,CAAA,EAAG,MAAA,CAAO,EAAE,QAAA,EAAU,QAAQ,CAAC,CAAA,4CAAA,EAA+C,CAAA,CAAE,GAAG,CAAA,MAAA,EAAI,CAAA,CAAE,GAAG,CAAA,CAAA,CAAA,GAC5F,EAAA;AAAA,MACJ,CAAA,CAAE,WAAW,CAAA,EAAG,MAAA,CAAO,EAAE,QAAA,EAAU,QAAQ,CAAC,CAAA,4BAAA,CAAA,GAAiC;AAAA,MAE5E,MAAA,CAAO,OAAO,EACd,IAAA,CAAK,GAAG,GACb,CAAA,GACE,IAAA;AAAA,oBACJA,IAAC,IAAA,EAAA,EAAG,SAAA,EAAU,aAAY,YAAA,EAAW,kBAAA,EAClC,WAAC,GAAG,CAAA,CAAE,OAAO,CAAA,CAAE,OAAA,GAAU,GAAA,CAAI,CAAC,sBAC7BE,IAAAA,CAAC,IAAA,EAAA,EAAiB,SAAA,EAAU,8DAAA,EAC1B,QAAA,EAAA;AAAA,sBAAAA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sCAAA,EACb,QAAA,EAAA;AAAA,QAAA,CAAA,CAAE,KAAA;AAAA,QACF,CAAA,CAAE,IAAA,KAAS,QAAA,mBAAWF,GAAAA,CAAC,QAAK,SAAA,EAAU,qBAAA,EAAsB,YAAA,EAAW,OAAA,EAAQ,CAAA,GAAK;AAAA,OAAA,EACvF,CAAA;AAAA,sBACAA,GAAAA,CAAC,GAAA,EAAA,EAAI,KAAA,EAAQ,CAAA,CAAE,KAAA,GAAQ,IAAA,GAAQ,GAAA,EAAK,GAAA,EAAK,CAAA,CAAE,KAAA,IAAS,MAAA,EAAQ,CAAA;AAAA,sBAC5DA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EAAiD,YAAE,KAAA,EAAM;AAAA,KAAA,EAAA,EANlE,CAAA,CAAE,KAOX,CACD,CAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ;AAGA,SAAS,UAAA,CAAW,EAAE,CAAA,EAAE,EAAyB;AAC/C,EAAA,IAAI,CAAA,CAAE,SAAA,KAAc,SAAA,IAAa,CAAA,CAAE,cAAc,QAAA,EAAU;AACzD,IAAA,MAAM,GAAA,GAAM,EAAE,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,MAAM,CAAA;AACpD,IAAA,MAAM,EAAA,GAAK,EAAE,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,OAAO,CAAA;AACpD,IAAA,uBACEE,KAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAAF,GAAAA,CAAC,UAAK,SAAA,EAAU,kDAAA,EAAmD,eAAW,IAAA,EAC5E,QAAA,kBAAAA,IAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qBAAoB,KAAA,EAAO,EAAE,OAAO,CAAA,EAAG,GAAA,EAAK,WAAW,CAAC,CAAA,CAAA,CAAA,IAAO,CAAA,EACjF,CAAA;AAAA,sBACAE,IAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,wCAAA,EACV,QAAA,EAAA;AAAA,QAAA,GAAA,mBACCA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,wCAAA,EACb,QAAA,EAAA;AAAA,UAAA,GAAA,CAAI,KAAA;AAAA,UAAM,QAAA;AAAA,UAAI,GAAA,CAAI,KAAA;AAAA,UAAM,IAAA;AAAA,UAAG,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,OAAO,CAAA;AAAA,UAAE;AAAA,SAAA,EACtD,CAAA,GACE,IAAA;AAAA,QACH,EAAA,mBACCA,IAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,uBAAA,EACb,QAAA,EAAA;AAAA,UAAA,EAAA,CAAG,KAAA;AAAA,UAAM,QAAA;AAAA,UAAI,EAAA,CAAG;AAAA,SAAA,EACnB,CAAA,GACE;AAAA,OAAA,EACN;AAAA,KAAA,EACF,CAAA;AAAA,EAEJ;AACA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AACzD,EAAA,uBACEA,KAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAF,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,WAAA,EACX,QAAA,EAAA,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,qBACdE,IAAAA,CAAC,IAAA,EAAA,EAAiB,WAAU,yEAAA,EAC1B,QAAA,EAAA;AAAA,sBAAAF,GAAAA,CAAC,UAAK,SAAA,EAAU,UAAA,EAAW,OAAO,CAAA,CAAE,KAAA,EACjC,YAAE,KAAA,EACL,CAAA;AAAA,sBACAA,GAAAA,CAAC,GAAA,EAAA,EAAI,OAAQ,CAAA,CAAE,KAAA,GAAQ,OAAQ,GAAA,EAAK,CAAA;AAAA,sBACpCE,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iEAAA,EACb,QAAA,EAAA;AAAA,QAAA,CAAA,CAAE,KAAA;AAAA,QAAM,QAAA;AAAA,QAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,OAAO,CAAA;AAAA,QAAE;AAAA,OAAA,EACrC;AAAA,KAAA,EAAA,EAPO,CAAA,CAAE,KAQX,CACD,CAAA,EACH,CAAA;AAAA,IACC,CAAA,CAAE,2BAAWF,GAAAA,CAAC,OAAE,SAAA,EAAU,+BAAA,EAAgC,8CAAgC,CAAA,GAAO;AAAA,GAAA,EACpG,CAAA;AAEJ;AAEA,SAAS,QAAA,CAAS;AAAA,EAChB,CAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,UAAU,CAAA;AAC7C,EAAA,MAAM,IAAA,GAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,GAAS,KAAA;AAChC,EAAA,uBACEE,KAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAF,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,WAAA,EACX,QAAA,EAAA,CAAA,CAAE,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM;AACpC,MAAA,MAAM,IAAA,GAAO,UAAA,GAAa,CAAA,CAAE,EAAE,CAAA;AAC9B,MAAA,uBACEE,IAAAA,CAAC,IAAA,EAAA,EAAc,SAAA,EAAU,+BAAA,EACvB,QAAA,EAAA;AAAA,wBAAAA,IAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yCAAA,EAA0C,QAAA,EAAA;AAAA,UAAA,QAAA;AAAA,UAAE,CAAA,CAAE,IAAA;AAAA,UAAK;AAAA,SAAA,EAAC,CAAA;AAAA,wBACjEA,IAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EACV,QAAA,EAAA;AAAA,UAAAC,QAAAA,CAAS,CAAA,CAAE,IAAA,EAAM,KAAK,CAAA;AAAA,UACtB,IAAA,mBAAOD,IAAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,YAAA,QAAA;AAAA,YAAI;AAAA,WAAA,EAAK,CAAA,GAAM;AAAA,SAAA,EAC3B;AAAA,OAAA,EAAA,EALO,EAAE,EAMX,CAAA;AAAA,IAEJ,CAAC,CAAA,EACH,CAAA;AAAA,IACC,OAAO,CAAA,mBACNA,KAACE,MAAAA,EAAA,EAAO,SAAQ,OAAA,EAAQ,IAAA,EAAK,MAAK,SAAA,EAAU,YAAA,EAAa,SAAS,MAAM,QAAA,CAAS,CAAC,CAAA,KAAM,CAAA,GAAI,SAAS,CAAA,EAAG,QAAA,EAAA;AAAA,MAAA,aAAA;AAAA,MAC1F,IAAA;AAAA,MAAK;AAAA,KAAA,EACnB,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;AAGO,SAAS,mBAAA,CAAoB;AAAA,EAClC,OAAA,EAAS,CAAA;AAAA,EACT,KAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,CAAA,CAAE,SAAS,CAAA,IAAK,IAAA;AACnC,EAAA,MAAM,OAAA,GAAU,CAAA,CAAE,IAAA,KAAS,OAAA,IAAW,CAAA,CAAE,OAAA,KAAY,IAAA,GAAO,CAAA,cAAA,EAAc,CAAA,CAAE,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,GAAK,EAAA;AAClG,EAAA,uBACEJ,GAAAA;AAAA,IAACK,aAAAA;AAAA,IAAA;AAAA,MACC,IAAA,kBAAML,GAAAA,CAAC,IAAA,EAAA,EAAK,CAAA;AAAA,MACZ,KAAA,EAAO,EAAE,KAAA,IAAS,mBAAA;AAAA,MAClB,IAAA,EAAM,CAAA,CAAE,KAAA,GAAQ,CAAA,EAAG,MAAA,CAAO,CAAA,CAAE,KAAA,EAAO,QAAQ,CAAC,CAAA,EAAG,OAAO,CAAA,CAAA,GAAK,gBAAA;AAAA,MAC3D,MAAA,EAAQ,CAAA,QAAA,EAAW,CAAA,CAAE,GAAG,CAAA,CAAA;AAAA,MAEvB,QAAA,EAAA,CAAA,CAAE,KAAA,GAAQ,CAAA,GACT,CAAA,CAAE,IAAA,KAAS,0BACTA,GAAAA,CAAC,SAAA,EAAA,EAAU,CAAA,EAAM,CAAA,GACf,CAAA,CAAE,SAAS,QAAA,mBACbA,GAAAA,CAAC,UAAA,EAAA,EAAW,CAAA,EAAM,CAAA,mBAElBA,GAAAA,CAAC,QAAA,EAAA,EAAS,CAAA,EAAM,KAAA,EAAc,UAAA,EAAwB,CAAA,GAEtD;AAAA;AAAA,GACN;AAEJ;AAOO,SAAS,oBAAA,CAAqB;AAAA,EACnC,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA,GAAY,KAAA;AAAA,EACZ,UAAA,GAAa,kBAAA;AAAA,EACb,gBAAA;AAAA,EACA,cAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAcG;AACD,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBACEE,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,EAAA,CAAG,WAAA,EAAa,SAAS,CAAA,EACvC,QAAA,EAAA;AAAA,sBAAAF,GAAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,wBAAA,EAAyB,CAAA;AAAA,sBAC7CA,GAAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,wBAAA,EAAyB;AAAA,KAAA,EAC/C,CAAA;AAAA,EAEJ;AACA,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,uBACEA,GAAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAMM,KAAAA;AAAA,QACN,KAAA,EAAO,UAAA;AAAA,QACN,GAAI,gBAAA,GAAmB,EAAE,WAAA,EAAa,gBAAA,KAAqB,EAAC;AAAA,QAC7D,UAAA,EAAY,CAAC,CAAC,cAAA;AAAA,QACb,GAAI,cAAA,GAAiB,EAAE,cAAA,KAAmB;AAAC;AAAA,KAC9C;AAAA,EAEJ;AACA,EAAA,uBACEN,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,GAAG,6BAAA,EAA+B,SAAS,CAAA,EACxD,QAAA,EAAA,SAAA,CAAU,GAAA,CAAI,CAAC,sBACdA,GAAAA,CAAC,uBAAgC,OAAA,EAAS,CAAA,EAAG,OAAc,UAAA,EAAA,EAAjC,CAAA,CAAE,GAAuD,CACpF,CAAA,EACH,CAAA;AAEJ;AC5PA,IAAMO,OAAAA,GAAS,CAAC,CAAA,EAAW,GAAA,EAAa,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,CAAA,KAAQ,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAA,KAAM,CAAA,GAAI,MAAM,IAAI,CAAA,CAAA;AAUlF,SAAS,iBAAA,CAAkB;AAAA,EAChC,QAAA;AAAA,EACA,OAAA,EAAS,YAAA;AAAA,EACT,SAAA,GAAY,KAAA;AAAA,EACZ,KAAA,GAAQ,sBAAA;AAAA,EACR;AACF,CAAA,EAOG;AACD,EAAA,IAAI,SAAA,EAAW,uBAAOP,GAAAA,CAACQ,QAAAA,EAAA,EAAS,SAAA,EAAWC,EAAAA,CAAG,wBAAA,EAA0B,SAAS,CAAA,EAAG,CAAA;AACpF,EAAA,MAAM,OAAA,GAAU,YAAA,IAAgB,QAAA,CAAS,CAAC,GAAG,KAAA,IAAS,CAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,GAAG,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAC,CAAA;AAC3D,EAAA,uBACET,GAAAA;AAAA,IAACK,aAAAA;AAAA,IAAA;AAAA,MACC,IAAA,kBAAML,GAAAA,CAAC,2BAAA,EAAA,EAA4B,CAAA;AAAA,MACnC,KAAA;AAAA,MACA,IAAA,EAAM,UAAU,CAAA,EAAGO,OAAAA,CAAO,SAAS,QAAA,EAAU,QAAQ,CAAC,CAAA,QAAA,CAAA,GAAa,wBAAA;AAAA,MACnE,SAAA;AAAA,MACA,MAAA,EAAO,UAAA;AAAA,MAEN,QAAA,EAAA,OAAA,mBACCP,GAAAA,CAAC,IAAA,EAAA,EAAG,WAAU,WAAA,EACX,QAAA,EAAA,QAAA,CAAS,IAAI,CAAC,CAAA,EAAG,sBAChBE,IAAAA,CAAC,QAAe,SAAA,EAAU,qBAAA,EAAsB,eAAa,CAAA,SAAA,EAAY,CAAA,CAAE,GAAG,CAAA,CAAA,EAC5E,QAAA,EAAA;AAAA,wBAAAA,IAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,2CAAA,EACX,QAAA,EAAA;AAAA,0BAAAA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qBAAA,EACd,QAAA,EAAA;AAAA,4BAAAA,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oCAAA,EAAsC,QAAA,EAAA;AAAA,cAAA,CAAA,GAAI,CAAA;AAAA,cAAE;AAAA,aAAA,EAAE,CAAA;AAAA,YAC7D,EAAE,KAAA,IAAS;AAAA,WAAA,EACd,CAAA;AAAA,0BACAF,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+DAAA,EACb,QAAA,EAAA,CAAA,CAAE,OAAA,KAAY,IAAA,GAAO,QAAA,GAAM,CAAA,EAAG,CAAA,CAAE,OAAO,CAAA,UAAA,CAAA,EAC1C;AAAA,SAAA,EACF,CAAA;AAAA,wBACAA,GAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,iDAAA,EAAkD,aAAA,EAAW,MAC3E,QAAA,kBAAAA,GAAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAWS,EAAAA;AAAA,cACT,2BAAA;AAAA,cACA,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,KAAY,QAAQ,YAAA,GAAe;AAAA,aACpD;AAAA,YACA,OAAO,EAAE,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,IAAW,CAAC,CAAA,CAAA,CAAA;AAAI;AAAA,SACvC,EACF,CAAA;AAAA,wBACAP,IAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,+BAAA,EACV,QAAA,EAAA;AAAA,UAAAK,OAAAA,CAAO,CAAA,CAAE,KAAA,EAAO,MAAM,CAAA;AAAA,UAAE,QAAA;AAAA,UAAI,CAAA,CAAE,OAAA;AAAA,UAAQ;AAAA,SAAA,EACzC;AAAA,OAAA,EAAA,EArBO,CAAA,CAAE,GAsBX,CACD,CAAA,EACH,CAAA,GACE;AAAA;AAAA,GACN;AAEJ;ACjEA,IAAM,6BAAa,IAAI,GAAA,CAAI,CAAC,YAAA,EAAc,YAAY,CAAC,CAAA;AAIvD,SAAS,KAAA,CAAM,EAAE,KAAA,EAAO,UAAA,EAAW,EAA+E;AAChH,EAAA,MAAM,CAAC,UAAU,WAAW,CAAA,GAAIG,SAAmB,EAAE,KAAA,EAAO,WAAW,CAAA;AACvE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAS,KAAK,CAAA;AAI1C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAA,GAAO,IAAA;AACX,IAAA,WAAA,CAAY,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA;AAChC,IAAA,SAAA,CAAU,KAAK,CAAA;AACf,IAAA,UAAA,CAAW,KAAK,CAAA,CACb,IAAA,CAAK,CAAC,GAAA,KAAQ,IAAA,IAAQ,WAAA,CAAY,GAAA,GAAM,EAAE,KAAA,EAAO,OAAA,EAAS,GAAA,EAAI,GAAI,EAAE,KAAA,EAAO,SAAA,EAAW,CAAC,CAAA,CACvF,KAAA,CAAM,MAAM,IAAA,IAAQ,WAAA,CAAY,EAAE,KAAA,EAAO,SAAA,EAAW,CAAC,CAAA;AACxD,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,GAAO,KAAA;AAAA,IACT,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,CAAM,EAAE,CAAC,CAAA;AAEb,EAAA,MAAM,IAAA,GAAO,2EAAA;AACb,EAAA,IAAI,QAAA,CAAS,KAAA,KAAU,SAAA,EAAW,uBAAOV,GAAAA,CAACQ,QAAAA,EAAA,EAAS,SAAA,EAAU,oBAAA,EAAqB,YAAA,EAAY,CAAA,QAAA,EAAW,KAAA,CAAM,IAAI,CAAA,CAAA,EAAI,CAAA;AACvH,EAAA,IAAI,QAAA,CAAS,UAAU,SAAA,EAAW;AAChC,IAAA,uBACEN,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAWO,EAAAA,CAAG,IAAA,EAAM,+FAA+F,CAAA,EACtH,QAAA,EAAA;AAAA,sBAAAT,GAAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,QAAA,EAAS,eAAY,MAAA,EAAO,CAAA;AAAA,sBAChDA,GAAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAA,mBAAA,EAAiB;AAAA,KAAA,EACzB,CAAA;AAAA,EAEJ;AACA,EAAA,IAAI,UAAU,UAAA,CAAW,GAAA,CAAI,MAAM,IAAA,CAAK,WAAA,EAAa,CAAA,EAAG;AACtD,IAAA,uBACEE,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAWO,EAAAA,CAAG,IAAA,EAAM,yEAAyE,CAAA,EAChG,QAAA,EAAA;AAAA,sBAAAT,GAAAA,CAACW,KAAA,EAAA,EAAU,SAAA,EAAU,8BAAA,EAA+B,eAAY,MAAA,EAAO,CAAA;AAAA,sBACvEX,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,8CAAA,EAAgD,gBAAM,IAAA,EAAK,CAAA;AAAA,sBAC3EE,IAAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,MAAM,QAAA,CAAS,GAAA;AAAA,UACf,MAAA,EAAO,QAAA;AAAA,UACP,GAAA,EAAI,YAAA;AAAA,UACJ,SAAA,EAAU,4FAAA;AAAA,UACX,QAAA,EAAA;AAAA,YAAA,OAAA;AAAA,4BACMF,GAAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAU,QAAA,EAAS,eAAY,MAAA,EAAO,CAAA;AAAA,4BACzDA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,gBAAM,IAAA,EAAK;AAAA;AAAA;AAAA;AACxC,KAAA,EACF,CAAA;AAAA,EAEJ;AACA,EAAA,uBACEA,GAAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,MAAM,QAAA,CAAS,GAAA;AAAA,MACf,MAAA,EAAO,QAAA;AAAA,MACP,GAAA,EAAI,YAAA;AAAA,MACJ,SAAA,EAAWS,EAAAA,CAAG,IAAA,EAAM,oHAAoH,CAAA;AAAA,MACxI,OAAO,KAAA,CAAM,IAAA;AAAA,MAEb,0BAAAT,GAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,QAAA,CAAS,KAAK,GAAA,EAAK,KAAA,CAAM,IAAA,EAAM,OAAA,EAAQ,QAAO,SAAA,EAAU,wBAAA,EAAyB,SAAS,MAAM,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA;AAAA,GAC7H;AAEJ;AAQO,SAAS,WAAA,CAAY;AAAA,EAC1B,MAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,IAAI,CAAC,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAC3B,EAAA,uBACEA,GAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAWS,EAAAA,CAAG,sBAAA,EAAwB,SAAS,CAAA,EAAG,YAAA,EAAW,QAAA,EAAS,aAAA,EAAa,MAAA,EACpF,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,qBACXT,GAAAA,CAAC,IAAA,EAAA,EACC,QAAA,kBAAAA,GAAAA,CAAC,KAAA,EAAA,EAAM,KAAA,EAAc,UAAA,EAAwB,CAAA,EAAA,EADtC,KAAA,CAAM,EAEf,CACD,CAAA,EACH,CAAA;AAEJ","file":"index.js","sourcesContent":["// The resource workspace's components moved to genesis-ui\n// (`@marktiderman/genesis-ui/resource`). These names stay here, deprecated, so existing\n// imports keep working; where genesis-ui's default words are neutral (\"Share your page\"),\n// the form's words are passed from here, so nothing a form shows changes.\nimport type { ComponentProps } from \"react\";\nimport {\n Chip as UiChip,\n FollowUpList as UiFollowUpList,\n HeadlineNumbers as UiHeadlineNumbers,\n ReadinessChip as UiReadinessChip,\n ResourceHeader as UiResourceHeader,\n ResourceSettingsPage as UiResourceSettingsPage,\n ResponsesToolbar as UiResponsesToolbar,\n SettingsSection as UiSettingsSection,\n ShareDialog as UiShareDialog,\n SummaryCard as UiSummaryCard,\n type FollowUpEntry as UiFollowUpEntry,\n type HeadlineNumber as UiHeadlineNumber,\n type ResourceHeaderProps as UiResourceHeaderProps,\n type ResourceSettingsSection,\n type ResponsesView as UiResponsesView,\n} from \"@marktiderman/genesis-ui/resource\";\nimport { FORM_READINESS_LABELS } from \"./moved-rules\";\n\n/** A form's Share dialog words: \"Share your form\", \"Anyone with the link can answer.\" */\nexport const FORM_SHARE_LABELS = {\n noun: \"form\",\n description: \"Anyone with the link can answer.\",\n} as const;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type ResourceHeaderProps = UiResourceHeaderProps;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type ResponsesView = UiResponsesView;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type HeadlineNumber = UiHeadlineNumber;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type FollowUpEntry = UiFollowUpEntry;\n/** @deprecated import `ResourceSettingsSection` from @marktiderman/genesis-ui */\nexport type SettingsPageSection = ResourceSettingsSection;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const ResourceHeader: typeof UiResourceHeader = UiResourceHeader;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const Chip: typeof UiChip = UiChip;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const ResponsesToolbar: typeof UiResponsesToolbar = UiResponsesToolbar;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const HeadlineNumbers: typeof UiHeadlineNumbers = UiHeadlineNumbers;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const SummaryCard: typeof UiSummaryCard = UiSummaryCard;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const FollowUpList: typeof UiFollowUpList = UiFollowUpList;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const SettingsSection: typeof UiSettingsSection = UiSettingsSection;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const ResourceSettingsPage: typeof UiResourceSettingsPage = UiResourceSettingsPage;\n\n/**\n * \"Ready to publish\", or how many problems to fix, in a form's words (\"Add a question\").\n * @deprecated import from @marktiderman/genesis-ui and pass `labels={FORM_READINESS_LABELS}`\n */\nexport function ReadinessChip({ labels, ...props }: ComponentProps<typeof UiReadinessChip>) {\n return <UiReadinessChip {...props} labels={{ ...FORM_READINESS_LABELS, ...labels }} />;\n}\n\n/**\n * Sharing a published form: \"Share your form\", \"Anyone with the link can answer.\"\n * @deprecated import from @marktiderman/genesis-ui and pass `{...FORM_SHARE_LABELS}`\n */\nexport function ShareDialog({\n noun = FORM_SHARE_LABELS.noun,\n description = FORM_SHARE_LABELS.description,\n ...props\n}: ComponentProps<typeof UiShareDialog>) {\n return <UiShareDialog {...props} noun={noun} description={description} />;\n}\n","import { GitBranch, Inbox, ListChecks, Settings } from \"lucide-react\";\nimport type { FormTab } from \"./status\";\n\n/** The form page's four places' icons, for `formNavItems(path, counts, FORM_NAV_ICONS)`. */\nexport const FORM_NAV_ICONS = {\n questions: ListChecks,\n logic: GitBranch,\n responses: Inbox,\n settings: Settings,\n} satisfies Record<FormTab, unknown>;\n","import type { ReactNode } from \"react\";\nimport {\n Button,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@marktiderman/genesis-ui\";\nimport { CalendarDays, CircleDashed, TriangleAlert, X } from \"lucide-react\";\nimport { lowThisWeek, NO_FILTERS, STATUS_FILTER_LABEL, type FiltersValue, type StatusFilter } from \"./summary\";\n\n/** One \"pick a value\" filter over an extra column, such as a location or a staff member. */\nexport interface ChoiceFilter {\n key: string;\n /** \"Any class\": what the menu says when nothing is picked. */\n allLabel: string;\n /** For screen readers: \"Class\". */\n label: string;\n options: string[];\n /** Shown before the value, e.g. a person icon for a staff member. */\n icon?: ReactNode;\n}\n\nconst WHEN: { value: FiltersValue[\"when\"]; label: string }[] = [\n { value: \"all\", label: \"All time\" },\n { value: \"today\", label: \"Today\" },\n { value: \"week\", label: \"This week\" },\n { value: \"7d\", label: \"Last 7 days\" },\n { value: \"30d\", label: \"Last 30 days\" },\n { value: \"month\", label: \"This month\" },\n { value: \"custom\", label: \"Pick dates\" },\n];\nconst ANY = \"__any\";\nconst TRIGGER = \"h-9 w-auto min-w-0 gap-2 [&>span]:flex [&>span]:items-center [&>span]:gap-2\";\n\n/**\n * Filters for a form's responses: when, the status (with `statuses`: Sent and partial,\n * Sent, Partial, In progress), any number of choice filters, a rating floor, and the\n * low-ratings chip (\"Low ratings this week\" until it's on; then a chip saying what low\n * means, with ×). The summary and the list of responses share one value.\n */\nexport function ResponsesFilters({\n value,\n onChange,\n choices = [],\n ratingMax = null,\n lowLabel = null,\n statuses = false,\n filtered,\n}: {\n /** Show the status filter: for a form that saves answers as they go (settings.saveProgress). */\n statuses?: boolean | undefined;\n value: FiltersValue;\n onChange: (next: FiltersValue) => void;\n choices?: readonly ChoiceFilter[] | undefined;\n /** The highest rating any question asks for (highestRating); no rating filter when null. */\n ratingMax?: number | null | undefined;\n /** What counts as low (lowRatingLabel); no low-ratings chip when null. */\n lowLabel?: string | null | undefined;\n /** Whether anything is left out (isFiltered), for Clear filters. */\n filtered: boolean;\n}) {\n const ratings = ratingMax ? Array.from({ length: Math.min(ratingMax, 10) - 1 }, (_, i) => i + 1) : [];\n return (\n <div className=\"flex flex-wrap items-center gap-2\" data-testid=\"responses-filters\">\n <Select value={value.when} onValueChange={(when) => onChange({ ...value, when: when as FiltersValue[\"when\"] })}>\n <SelectTrigger className={TRIGGER} aria-label=\"When\">\n <CalendarDays className=\"size-4 text-muted-foreground\" aria-hidden />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {WHEN.map((w) => (\n <SelectItem key={w.value} value={w.value}>\n {w.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {value.when === \"custom\" ? (\n <span className=\"flex items-center gap-1\">\n <Input\n type=\"date\"\n className=\"h-9 w-auto\"\n aria-label=\"From\"\n value={value.from}\n max={value.to || undefined}\n onChange={(e) => onChange({ ...value, from: e.target.value })}\n />\n <span className=\"text-sm text-muted-foreground\">to</span>\n <Input\n type=\"date\"\n className=\"h-9 w-auto\"\n aria-label=\"To\"\n value={value.to}\n min={value.from || undefined}\n onChange={(e) => onChange({ ...value, to: e.target.value })}\n />\n </span>\n ) : null}\n {statuses ? (\n <Select\n value={value.status ?? \"counted\"}\n onValueChange={(status) => onChange({ ...value, status: status as StatusFilter })}\n >\n <SelectTrigger className={TRIGGER} aria-label=\"Status\" data-testid=\"responses-status\">\n <CircleDashed className=\"size-4 text-muted-foreground\" aria-hidden />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(STATUS_FILTER_LABEL) as StatusFilter[]).map((s) => (\n <SelectItem key={s} value={s}>\n {STATUS_FILTER_LABEL[s]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n {choices\n .filter((c) => c.options.length > 0)\n .map((c) => (\n <Select\n key={c.key}\n value={value.match[c.key] || ANY}\n onValueChange={(v) => onChange({ ...value, match: { ...value.match, [c.key]: v === ANY ? \"\" : v } })}\n >\n <SelectTrigger className={`${TRIGGER} max-w-56`} aria-label={c.label}>\n {c.icon ? (\n <span className=\"text-muted-foreground [&_svg]:size-4\" aria-hidden>\n {c.icon}\n </span>\n ) : null}\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ANY}>{c.allLabel}</SelectItem>\n {c.options.map((o) => (\n <SelectItem key={o} value={o}>\n {o}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ))}\n {ratings.length > 0 ? (\n <Select\n value={value.ratingAtMost == null ? ANY : String(value.ratingAtMost)}\n onValueChange={(v) => onChange({ ...value, ratingAtMost: v === ANY ? null : Number(v) })}\n >\n <SelectTrigger className={TRIGGER} aria-label=\"Rating\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ANY}>Any rating</SelectItem>\n {ratings.map((r) => (\n <SelectItem key={r} value={String(r)}>\n {r === 1 ? \"Rated 1\" : `Rated ${r} or below`}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n {lowLabel ? (\n value.low ? (\n <span\n className=\"inline-flex h-9 items-center gap-1.5 rounded-md bg-warning/15 pl-2.5 pr-1 text-sm text-amber-800 dark:bg-warning/20 dark:text-amber-200\"\n data-testid=\"low-ratings-chip\"\n >\n <TriangleAlert className=\"size-4\" aria-hidden />\n {`Low ratings (${lowLabel})`}\n <button\n type=\"button\"\n aria-label=\"Show every rating\"\n className=\"rounded p-1 hover:bg-warning/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onClick={() => onChange({ ...value, low: false })}\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n </span>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-9\"\n startIcon={<TriangleAlert className=\"size-4\" />}\n onClick={() => onChange(lowThisWeek(value))}\n data-testid=\"low-ratings-preset\"\n >\n Low ratings this week\n </Button>\n )\n ) : null}\n {filtered ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-9\" onClick={() => onChange(NO_FILTERS)}>\n Clear filters\n </Button>\n ) : null}\n </div>\n );\n}\n","import { useState, type ComponentType, type ReactNode } from \"react\";\nimport { Button, EmptyState, Skeleton, cn } from \"@marktiderman/genesis-ui\";\nimport {\n CircleCheck,\n CircleDot,\n Gauge,\n Inbox,\n ListChecks,\n SquareCheck,\n Star,\n Type,\n type LucideProps,\n} from \"lucide-react\";\nimport { dayLabel, SummaryCard } from \"@marktiderman/genesis-ui/resource\";\nimport { lowScaleAtMost } from \"./summary\";\nimport type { ChoiceSummary, QuestionSummary, ScaleSummary, TextSummary } from \"./summary\";\n\nconst FIRST_TEXT = 5;\nconst MORE_TEXT = 10;\n\nconst plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;\n\nconst ICONS: Record<string, ComponentType<LucideProps>> = {\n rating: Star,\n nps: Gauge,\n consent: SquareCheck,\n \"yes-no\": CircleCheck,\n \"single-choice\": CircleDot,\n dropdown: CircleDot,\n \"multi-choice\": ListChecks,\n};\n\n/** A bar as wide as its share; low scores in the warning colour. */\nfunction Bar({ share, low = false }: { share: number; low?: boolean }) {\n return (\n <span className=\"h-2 overflow-hidden rounded-full bg-muted\" aria-hidden>\n <span\n className={cn(\"block h-full rounded-full\", low ? \"bg-warning\" : \"bg-primary\")}\n style={{ width: `${Math.max(0, Math.min(100, share))}%` }}\n />\n </span>\n );\n}\n\nfunction ScaleBody({ s }: { s: ScaleSummary }) {\n const most = Math.max(1, ...s.buckets.map((b) => b.count));\n const atMost = lowScaleAtMost(s.type, s.max);\n return (\n <>\n {s.nps ? (\n <p className=\"text-sm\">\n <span className=\"text-2xl font-semibold tabular-nums\">{s.nps.score}</span>{\" \"}\n <span className=\"text-muted-foreground\">NPS</span>\n <span className=\"block text-xs text-muted-foreground\">\n {plural(s.nps.promoters, \"promoter\")} (9–10), {plural(s.nps.passives, \"passive\")} (7–8),{\" \"}\n {plural(s.nps.detractors, \"detractor\")} (0–6)\n </span>\n </p>\n ) : null}\n {s.rescaled || s.excluded ? (\n <p className=\"text-xs text-muted-foreground\" data-testid={`scale-note-${s.key}`}>\n {[\n s.rescaled\n ? `${plural(s.rescaled, \"answer\")} from an earlier version's scale moved onto ${s.min}–${s.max}.`\n : \"\",\n s.excluded ? `${plural(s.excluded, \"answer\")} outside the scale left out.` : \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n </p>\n ) : null}\n <ul className=\"space-y-2\" aria-label=\"Answers by score\">\n {[...s.buckets].reverse().map((b) => (\n <li key={b.value} className=\"grid grid-cols-[2.25rem_1fr_2rem] items-center gap-3 text-sm\">\n <span className=\"flex items-center gap-1 tabular-nums\">\n {b.value}\n {s.type === \"rating\" ? <Star className=\"size-3 fill-current\" aria-label=\"stars\" /> : null}\n </span>\n <Bar share={(b.count / most) * 100} low={b.value <= atMost} />\n <span className=\"text-right tabular-nums text-muted-foreground\">{b.count}</span>\n </li>\n ))}\n </ul>\n </>\n );\n}\n\n/** Two-way questions (consent, yes/no) as one split bar; others as a bar per option. */\nfunction ChoiceBody({ s }: { s: ChoiceSummary }) {\n if (s.fieldType === \"consent\" || s.fieldType === \"yes-no\") {\n const yes = s.options.find((o) => o.value === \"true\");\n const no = s.options.find((o) => o.value === \"false\");\n return (\n <>\n <span className=\"flex h-2.5 overflow-hidden rounded-full bg-muted\" aria-hidden>\n <span className=\"h-full bg-primary\" style={{ width: `${yes?.percent ?? 0}%` }} />\n </span>\n <p className=\"flex flex-wrap gap-x-4 gap-y-1 text-sm\">\n {yes ? (\n <span className=\"text-emerald-700 dark:text-emerald-300\">\n {yes.label} · {yes.count} ({Math.round(yes.percent)}%)\n </span>\n ) : null}\n {no ? (\n <span className=\"text-muted-foreground\">\n {no.label} · {no.count}\n </span>\n ) : null}\n </p>\n </>\n );\n }\n const most = Math.max(1, ...s.options.map((o) => o.count));\n return (\n <>\n <ul className=\"space-y-2\">\n {s.options.map((o) => (\n <li key={o.value} className=\"grid grid-cols-[minmax(2rem,12rem)_1fr_auto] items-center gap-3 text-sm\">\n <span className=\"truncate\" title={o.label}>\n {o.label}\n </span>\n <Bar share={(o.count / most) * 100} />\n <span className=\"whitespace-nowrap text-right tabular-nums text-muted-foreground\">\n {o.count} · {Math.round(o.percent)}%\n </span>\n </li>\n ))}\n </ul>\n {s.multiple ? <p className=\"text-xs text-muted-foreground\">People could pick more than one.</p> : null}\n </>\n );\n}\n\nfunction TextBody({\n s,\n today,\n answerMeta,\n}: {\n s: TextSummary;\n today?: string | undefined;\n answerMeta?: ((id: string) => ReactNode) | undefined;\n}) {\n const [shown, setShown] = useState(FIRST_TEXT);\n const left = s.answers.length - shown;\n return (\n <>\n <ul className=\"space-y-3\">\n {s.answers.slice(0, shown).map((a) => {\n const meta = answerMeta?.(a.id);\n return (\n <li key={a.id} className=\"border-l-2 border-border pl-3\">\n <p className=\"whitespace-pre-wrap break-words text-sm\">“{a.text}”</p>\n <p className=\"text-xs text-muted-foreground\">\n {dayLabel(a.date, today)}\n {meta ? <> · {meta}</> : null}\n </p>\n </li>\n );\n })}\n </ul>\n {left > 0 ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"self-start\" onClick={() => setShown((n) => n + MORE_TEXT)}>\n Show more ({left} more)\n </Button>\n ) : null}\n </>\n );\n}\n\n/** One question's card: its type icon, title and answer count, then its spread. */\nexport function QuestionSummaryCard({\n summary: s,\n today,\n answerMeta,\n}: {\n summary: QuestionSummary;\n today?: string | undefined;\n answerMeta?: ((id: string) => ReactNode) | undefined;\n}) {\n const Icon = ICONS[s.fieldType] ?? Type;\n const average = s.kind === \"scale\" && s.average !== null ? ` · average ${s.average.toFixed(1)}` : \"\";\n return (\n <SummaryCard\n icon={<Icon />}\n title={s.label || \"Untitled question\"}\n meta={s.count ? `${plural(s.count, \"answer\")}${average}` : \"No answers yet\"}\n testID={`summary-${s.key}`}\n >\n {s.count > 0 ? (\n s.kind === \"scale\" ? (\n <ScaleBody s={s} />\n ) : s.kind === \"choice\" ? (\n <ChoiceBody s={s} />\n ) : (\n <TextBody s={s} today={today} answerMeta={answerMeta} />\n )\n ) : null}\n </SummaryCard>\n );\n}\n\n/**\n * A form's responses question by question (summarizeResponses): each rating or NPS\n * question's spread with low scores marked, counts for each choice, consent and yes/no\n * as one split bar, and the latest written answers.\n */\nexport function QuestionSummaryCards({\n summaries,\n responses,\n isLoading = false,\n emptyTitle = \"No responses yet\",\n emptyDescription,\n onClearFilters,\n today,\n answerMeta,\n className,\n}: {\n summaries: readonly QuestionSummary[];\n /** How many responses the summaries cover. */\n responses: number;\n isLoading?: boolean | undefined;\n emptyTitle?: string | undefined;\n emptyDescription?: string | undefined;\n /** Given while filters are on: an empty summary then says so, with a way out. */\n onClearFilters?: (() => void) | undefined;\n /** Today (YYYY-MM-DD) on the responses' clock, so written answers say \"Today\". */\n today?: string | undefined;\n /** Extra words after a written answer's day, by response id: \"6:00 WOD · rated 2\". */\n answerMeta?: ((id: string) => ReactNode) | undefined;\n className?: string | undefined;\n}) {\n if (isLoading) {\n return (\n <div className={cn(\"space-y-3\", className)}>\n <Skeleton className=\"h-40 w-full rounded-lg\" />\n <Skeleton className=\"h-32 w-full rounded-lg\" />\n </div>\n );\n }\n if (!responses) {\n return (\n <EmptyState\n icon={Inbox}\n title={emptyTitle}\n {...(emptyDescription ? { description: emptyDescription } : {})}\n hasFilters={!!onClearFilters}\n {...(onClearFilters ? { onClearFilters } : {})}\n />\n );\n }\n return (\n <div className={cn(\"flex min-w-0 flex-col gap-3\", className)}>\n {summaries.map((s) => (\n <QuestionSummaryCard key={s.key} summary={s} today={today} answerMeta={answerMeta} />\n ))}\n </div>\n );\n}\n","import { Skeleton, cn } from \"@marktiderman/genesis-ui\";\nimport { ChartNoAxesColumnDecreasing } from \"lucide-react\";\nimport { SummaryCard } from \"@marktiderman/genesis-ui/resource\";\nimport type { QuestionDropOff } from \"./dropoff\";\n\nconst plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;\n\n/**\n * Drop-off by question (`dropOffSummary`): how many people started, then for each question in\n * order how many reached it, how many stopped there, and that as a share, with the share as\n * a bar (the question most people left on in the warning colour). For a form that saves\n * answers as they go. Spread `dropOffSummary(...)` into it; without `started` it falls back\n * to the first question's views, which leaves out responses in progress and anyone logic\n * hid the first question from.\n */\nexport function DropOffByQuestion({\n dropOffs,\n started: startedCount,\n isLoading = false,\n title = \"Drop-off by question\",\n className,\n}: {\n dropOffs: readonly QuestionDropOff[];\n /** How many people started (`dropOffSummary`'s `started`). */\n started?: number | undefined;\n isLoading?: boolean | undefined;\n title?: string | undefined;\n className?: string | undefined;\n}) {\n if (isLoading) return <Skeleton className={cn(\"h-40 w-full rounded-lg\", className)} />;\n const started = startedCount ?? dropOffs[0]?.views ?? 0;\n const worst = Math.max(0, ...dropOffs.map((d) => d.stopped));\n return (\n <SummaryCard\n icon={<ChartNoAxesColumnDecreasing />}\n title={title}\n meta={started ? `${plural(started, \"person\", \"people\")} started` : \"Nobody has started yet\"}\n className={className}\n testID=\"drop-off\"\n >\n {started ? (\n <ol className=\"space-y-3\">\n {dropOffs.map((d, i) => (\n <li key={d.key} className=\"space-y-1.5 text-sm\" data-testid={`drop-off-${d.key}`}>\n <p className=\"flex items-baseline justify-between gap-3\">\n <span className=\"min-w-0 break-words\">\n <span className=\"text-muted-foreground tabular-nums\">{i + 1}. </span>\n {d.label || \"Untitled question\"}\n </span>\n <span className=\"shrink-0 whitespace-nowrap tabular-nums text-muted-foreground\">\n {d.dropOff === null ? \"–\" : `${d.dropOff}% drop-off`}\n </span>\n </p>\n <span className=\"block h-2 overflow-hidden rounded-full bg-muted\" aria-hidden>\n <span\n className={cn(\n \"block h-full rounded-full\",\n d.stopped && d.stopped === worst ? \"bg-warning\" : \"bg-primary\",\n )}\n style={{ width: `${d.dropOff ?? 0}%` }}\n />\n </span>\n <p className=\"text-xs text-muted-foreground\">\n {plural(d.views, \"view\")} · {d.stopped} stopped here\n </p>\n </li>\n ))}\n </ol>\n ) : null}\n </SummaryCard>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { ExternalLink, ImageOff, Image as ImageIcon } from \"lucide-react\";\nimport { cn, Skeleton } from \"@marktiderman/genesis-ui\";\nimport type { PhotoRef } from \"@marktiderman/genesis-forms\";\n\n/** Types most browsers can't draw (HEIC and HEIF): shown as a file tile with an Open link. */\nconst UNDRAWABLE = new Set([\"image/heic\", \"image/heif\"]);\n\ntype Resolved = { state: \"loading\" } | { state: \"ready\"; url: string } | { state: \"missing\" };\n\nfunction Photo({ photo, resolveUrl }: { photo: PhotoRef; resolveUrl: (ref: PhotoRef) => Promise<string | null> }) {\n const [resolved, setResolved] = useState<Resolved>({ state: \"loading\" });\n const [broken, setBroken] = useState(false);\n\n // Each photo's address is asked for once (per photo id); a signed link may expire, so\n // it isn't kept beyond this view.\n useEffect(() => {\n let live = true;\n setResolved({ state: \"loading\" });\n setBroken(false);\n resolveUrl(photo)\n .then((url) => live && setResolved(url ? { state: \"ready\", url } : { state: \"missing\" }))\n .catch(() => live && setResolved({ state: \"missing\" }));\n return () => {\n live = false;\n };\n }, [photo.id]); // eslint-disable-line react-hooks/exhaustive-deps -- resolveUrl is often an inline function\n\n const tile = \"relative size-28 overflow-hidden rounded-md border border-border bg-muted\";\n if (resolved.state === \"loading\") return <Skeleton className=\"size-28 rounded-md\" aria-label={`Loading ${photo.name}`} />;\n if (resolved.state === \"missing\") {\n return (\n <div className={cn(tile, \"flex flex-col items-center justify-center gap-1 p-2 text-center text-xs text-muted-foreground\")}>\n <ImageOff className=\"size-5\" aria-hidden=\"true\" />\n <span>Photo unavailable</span>\n </div>\n );\n }\n if (broken || UNDRAWABLE.has(photo.type.toLowerCase())) {\n return (\n <div className={cn(tile, \"flex flex-col items-center justify-center gap-1 p-2 text-center text-xs\")}>\n <ImageIcon className=\"size-5 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"line-clamp-2 break-all text-muted-foreground\">{photo.name}</span>\n <a\n href={resolved.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 font-medium text-primary underline-offset-4 hover:underline\"\n >\n Open <ExternalLink className=\"size-3\" aria-hidden=\"true\" />\n <span className=\"sr-only\">{photo.name}</span>\n </a>\n </div>\n );\n }\n return (\n <a\n href={resolved.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={cn(tile, \"block outline-none ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\")}\n title={photo.name}\n >\n <img src={resolved.url} alt={photo.name} loading=\"lazy\" className=\"size-full object-cover\" onError={() => setBroken(true)} />\n </a>\n );\n}\n\n/**\n * A response's photos as thumbnails, each opening full size in a new tab. Data-agnostic:\n * the host resolves each reference to an address it may show (a short-lived signed link,\n * say), or null when it can't. A photo most browsers can't draw (HEIC) is a tile with\n * its name and an Open link; one that can't be found says so.\n */\nexport function PhotoAnswer({\n photos,\n resolveUrl,\n className,\n testID,\n}: {\n photos: PhotoRef[];\n resolveUrl: (ref: PhotoRef) => Promise<string | null>;\n className?: string | undefined;\n testID?: string | undefined;\n}) {\n if (!photos.length) return null;\n return (\n <ul className={cn(\"flex flex-wrap gap-3\", className)} aria-label=\"Photos\" data-testid={testID}>\n {photos.map((photo) => (\n <li key={photo.id}>\n <Photo photo={photo} resolveUrl={resolveUrl} />\n </li>\n ))}\n </ul>\n );\n}\n"]}
|
package/dist/rules.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ interface SummaryItem {
|
|
|
49
49
|
date: string;
|
|
50
50
|
definition: FormDefinition;
|
|
51
51
|
answers: Record<string, Json>;
|
|
52
|
-
/** Extra plain values a filter can match, such as the
|
|
52
|
+
/** Extra plain values a filter can match, such as the location or staff member. */
|
|
53
53
|
extra?: Record<string, Cell>;
|
|
54
54
|
/** Default `completed`. */
|
|
55
55
|
status?: ResponseStatus | undefined;
|
package/dist/rules.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { FORM_READINESS_LABELS, FORM_READINESS_OPTIONS, NO_FILTERS, RESPONSE_STATUS_LABEL, SAVE_STATE_LABEL, SLUG_PATTERN, STATUS_FILTER_LABEL, answerCell, answerColumns, answersByKey, carryAnswers, comparisonFilter, copyTitle, dayLabel, dropOffByQuestion, dropOffSummary, embedSnippet, filterResponses, followUpOf, formAvailability, formCounts, formNavItems, formStatusChip, freeSlug, hasLowRating, hasLowRatingExcept, headlineCards, headlineNumbers, highestRating, isFiltered, isFull, lowRatingAtMost, lowRatingLabel, lowScaleAtMost, lowThisWeek, lowestRating, matchesStatus, needsFollowUp, offersSubmitAnother, parseInstant, plainLabel, prefilledUrl, presetRange, readinessChip, readinessOf, slugFromTitle, summarizeResponses, takesResponses, toCsv, toResponseFilter, validateSlug, valuesByKey } from './chunk-
|
|
1
|
+
export { FORM_READINESS_LABELS, FORM_READINESS_OPTIONS, NO_FILTERS, RESPONSE_STATUS_LABEL, SAVE_STATE_LABEL, SLUG_PATTERN, STATUS_FILTER_LABEL, answerCell, answerColumns, answersByKey, carryAnswers, comparisonFilter, copyTitle, dayLabel, dropOffByQuestion, dropOffSummary, embedSnippet, filterResponses, followUpOf, formAvailability, formCounts, formNavItems, formStatusChip, freeSlug, hasLowRating, hasLowRatingExcept, headlineCards, headlineNumbers, highestRating, isFiltered, isFull, lowRatingAtMost, lowRatingLabel, lowScaleAtMost, lowThisWeek, lowestRating, matchesStatus, needsFollowUp, offersSubmitAnother, parseInstant, plainLabel, prefilledUrl, presetRange, readinessChip, readinessOf, slugFromTitle, summarizeResponses, takesResponses, toCsv, toResponseFilter, validateSlug, valuesByKey } from './chunk-NQYZ7PHD.js';
|
|
2
2
|
//# sourceMappingURL=rules.js.map
|
|
3
3
|
//# sourceMappingURL=rules.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marktiderman/genesis-forms-studio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@marktiderman/genesis-design-system": "^1.5.0",
|
|
50
|
-
"@marktiderman/genesis-forms": "^0.9.
|
|
51
|
-
"@marktiderman/genesis-ui": "^2.
|
|
50
|
+
"@marktiderman/genesis-forms": "^0.9.2",
|
|
51
|
+
"@marktiderman/genesis-ui": "^2.15.0",
|
|
52
52
|
"@testing-library/react": "^16.3.2",
|
|
53
53
|
"@types/react": "^19.2.14",
|
|
54
54
|
"@types/react-dom": "^19.2.3",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/answers.ts","../src/summary.ts","../src/headline.ts","../src/dropoff.ts","../src/followups.ts","../src/availability.ts","../src/status.ts","../src/moved-rules.ts","../src/slug.ts","../src/respondent.ts"],"names":["addDays","at","UI_SAVE_STATE_LABEL","uiDayLabel","uiPrefilledUrl","uiEmbedSnippet","uiReadinessOf","uiReadinessChip"],"mappings":"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","file":"chunk-KUYYXBEN.js","sourcesContent":["// Turning genesis-forms answers into plain cells and columns. Shared by everything that\n// shows or exports answers: a Sheet or email delivery, a responses table, a CSV. Pure: no\n// storage, no React. Moved up from the host app's src/lib/forms/answers.ts.\nimport {\n summarizeValue,\n type FieldBlock,\n type FormDefinition,\n type Json,\n} from \"@marktiderman/genesis-forms\";\n\nexport type Cell = string | number | boolean;\n\n// carryAnswers moved to genesis-forms (an edit link's prefill runs where the engine does);\n// re-exported so the rules entry keeps it.\nexport { carryAnswers } from \"@marktiderman/genesis-forms\";\n\n// Option labels by value, built once per options array: answerCell runs once per answer, and\n// option lists can hold thousands of options. The first option with a value wins, as find() did.\n// Keys are the stored values as they are (a Map matches them like ===), so number and boolean\n// option values keep their labels too.\nconst labelMaps = new WeakMap<readonly { value: string; label?: string }[], Map<unknown, string | undefined>>();\nfunction optionLabels(options: readonly { value: string; label?: string }[]) {\n let map = labelMaps.get(options);\n if (!map) {\n map = new Map();\n for (const o of options) if (!map.has(o.value)) map.set(o.value, o.label);\n labelMaps.set(options, map);\n }\n return map;\n}\n\n/** One answer as a cell: option labels for choices, Yes/No, lists joined with commas. */\nexport function answerCell(field: FieldBlock, value: Json | undefined): Cell {\n if (value === undefined || value === null) return \"\";\n if (field.type === \"yes-no\")\n return value === true ? \"Yes\" : value === false ? \"No\" : String(value);\n if (field.type === \"consent\")\n return value === true ? \"Agreed\" : value === false ? \"Didn't agree\" : String(value);\n const options = Array.isArray(field.props?.[\"options\"])\n ? (field.props[\"options\"] as { value: string; label?: string }[])\n : [];\n const labels = optionLabels(options);\n const label = (v: Json) => labels.get(v) ?? String(v);\n // Structured values (a worksheet's rows, notes or highlights) use each type's own summary\n // from genesis-forms. Flat values keep raw numbers, so a Sheet can sort and average them.\n const structured = Array.isArray(value)\n ? value.some((v) => v !== null && typeof v === \"object\")\n : typeof value === \"object\";\n if (structured) {\n // A type genesis-forms doesn't know (yet) summarizes as \"[object Object]\": fall back to JSON.\n const summary = summarizeValue(value, field);\n return summary && !summary.includes(\"[object Object]\") ? summary : JSON.stringify(value);\n }\n if (Array.isArray(value)) return value.map(label).join(\", \");\n if (options.length) return label(value);\n return typeof value === \"number\" || typeof value === \"boolean\" ? value : String(value);\n}\n\n/** A label with recall tokens replaced by their fallback. */\nexport const plainLabel = (label: string) =>\n label.replace(/\\{\\{[^}|]*\\|?([^}]*)\\}\\}/g, (_, fallback: string) => fallback || \"…\");\n\nexport interface AnswerColumn {\n /** The field's key: stable across versions, so one column covers every version's answers. */\n key: string;\n label: string;\n}\n\n/**\n * One column per field key across the given definitions, in the order the newest\n * definition asks them, then keys only older versions had (in their order). Labels come\n * from the newest definition that has the key.\n */\nexport function answerColumns(\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): AnswerColumn[] {\n const columns: AnswerColumn[] = [];\n const seen = new Set<string>();\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind !== \"field\" || seen.has(block.key) || skip.has(block.key)) continue;\n seen.add(block.key);\n columns.push({ key: block.key, label: plainLabel(block.label) });\n }\n }\n return columns;\n}\n\n/** A response's answers by field key, as cells (answers are stored by field id). */\nexport function answersByKey(\n definition: FormDefinition,\n answers: Record<string, Json>,\n): Record<string, Cell> {\n const cells: Record<string, Cell> = {};\n for (const block of definition.blocks) {\n if (block.kind !== \"field\") continue;\n const value = answers[block.id];\n if (value !== undefined) cells[block.key] = answerCell(block, value);\n }\n return cells;\n}\n\n/** A response's raw answers by field key, with the field each was given to (answers are stored by field id). */\nexport function valuesByKey(\n definition: FormDefinition,\n answers: Record<string, Json>,\n): Map<string, { field: FieldBlock; value: Json }> {\n const values = new Map<string, { field: FieldBlock; value: Json }>();\n for (const block of definition.blocks) {\n if (block.kind !== \"field\") continue;\n const value = answers[block.id];\n if (value !== undefined && value !== null) values.set(block.key, { field: block, value });\n }\n return values;\n}\n\n/**\n * CSV text (RFC 4180, CRLF) with a header row; every cell is quoted when it needs to be.\n * Text that a spreadsheet would run as a formula (starting with = + - @, tab or CR) gets a\n * leading apostrophe, so a respondent's answer can't run in Excel when staff open the\n * download. Numbers stay as they are. (Sheets delivery writes RAW values and needs none.)\n */\nexport function toCsv(header: readonly string[], rows: readonly (readonly Cell[])[]): string {\n const quote = (v: Cell) => {\n const raw = String(v);\n const s = typeof v === \"string\" && /^[=+\\-@\\t\\r]/.test(raw) ? `'${raw}` : raw;\n return /[\",\\r\\n]/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [header, ...rows].map((r) => r.map(quote).join(\",\")).join(\"\\r\\n\") + \"\\r\\n\";\n}\n","// A form's responses, question by question, as a Summary tab shows them: the average and\n// spread of each rating or NPS question, counts for each choice, the latest text answers.\n// Also the filters a Summary and its table share (dates, extra columns such as a class, a\n// low rating). Built on answers.ts, so every version's answers count under one key. Pure:\n// no storage, no React. Moved up from the host app's src/lib/forms/summary.ts.\nimport {\n choiceOptions,\n isOtherValue,\n otherOption,\n type FieldBlock,\n type FormDefinition,\n type Json,\n} from \"@marktiderman/genesis-forms\";\nimport { answerColumns, answersByKey, valuesByKey, type Cell } from \"./answers\";\n\n/**\n * Where a response is, on a form that saves answers as they go (`settings.saveProgress`):\n * `in_progress` while someone is answering, `partial` once they stopped without sending\n * (kept, and counted like a sent one), `completed` once sent.\n */\nexport type ResponseStatus = \"in_progress\" | \"partial\" | \"completed\";\n\n/** One answered form (a feedback response, a worksheet entry). */\nexport interface SummaryItem {\n id: string;\n /** The day it was answered, YYYY-MM-DD. */\n date: string;\n definition: FormDefinition;\n answers: Record<string, Json>;\n /** Extra plain values a filter can match, such as the class or coach. */\n extra?: Record<string, Cell>;\n /** Default `completed`. */\n status?: ResponseStatus | undefined;\n /**\n * The furthest question reached (a field id of `definition`), for an unfinished\n * response: genesis-forms `formProgress`'s `fieldId`. Drop-off by question reads it.\n */\n furthest?: string | null | undefined;\n /**\n * Its hidden inputs, as stored. Drop-off by question rebuilds the respondent's path\n * from them and `answers`, so logic that reads a hidden input is followed.\n */\n hidden?: Record<string, Json> | undefined;\n /**\n * Answers the host keeps apart from `answers` (contact details on their own row, say),\n * by field key. Only the path reads them: summaries and filters don't.\n */\n extraAnswers?: Record<string, Json | null | undefined> | undefined;\n}\n\n/**\n * Which responses to show by status. `counted` (the default): sent and partial ones,\n * which summaries count; `in_progress` ones are still being answered.\n */\nexport type StatusFilter = \"counted\" | \"completed\" | \"partial\" | \"in_progress\";\n\n/** The status filter's words, in the menu's order. */\nexport const STATUS_FILTER_LABEL: Record<StatusFilter, string> = {\n counted: \"Sent and partial\",\n completed: \"Sent\",\n partial: \"Partial\",\n in_progress: \"In progress\",\n};\n\n/** A response status's word, as a table or a detail panel shows it. */\nexport const RESPONSE_STATUS_LABEL: Record<ResponseStatus, string> = {\n in_progress: \"In progress\",\n partial: \"Partial\",\n completed: \"Sent\",\n};\n\n/** Whether `item` passes a status filter (no status is `completed`). */\nexport function matchesStatus(item: Pick<SummaryItem, \"status\">, filter: StatusFilter = \"counted\"): boolean {\n const status = item.status ?? \"completed\";\n return filter === \"counted\" ? status !== \"in_progress\" : status === filter;\n}\n\nexport interface ScaleSummary {\n kind: \"scale\";\n key: string;\n label: string;\n type: \"rating\" | \"nps\";\n /** The field type, as for every summary. */\n fieldType: \"rating\" | \"nps\";\n /** How many responses answered it. */\n count: number;\n min: number;\n max: number;\n /** Null when no one answered. */\n average: number | null;\n /** One per value from min to max, in order, zeros included. */\n buckets: { value: number; count: number }[];\n /**\n * Answers given on an older version's different scale (a 1–10 rating now 1–5), moved\n * onto this one in proportion: they count, at their nearest point on this scale.\n */\n rescaled: number;\n /** Answers left out: outside their own question's scale, or not a whole number. */\n excluded: number;\n /** NPS only: promoters 9–10, passives 7–8, detractors 0–6, score = % promoters − % detractors. */\n nps: { promoters: number; passives: number; detractors: number; score: number } | null;\n}\n\nexport interface ChoiceSummary {\n kind: \"choice\";\n key: string;\n label: string;\n /** single-choice, multi-choice, dropdown, yes-no or consent. */\n fieldType: string;\n /** How many responses answered it. */\n count: number;\n /** Several options per response, so the percentages can add up to more than 100. */\n multiple: boolean;\n /** The newest version's options in order, then any only older versions had. */\n options: { value: string; label: string; count: number; percent: number }[];\n}\n\nexport interface TextSummary {\n kind: \"text\";\n key: string;\n label: string;\n /** The field type: short-text, long-text, email… */\n fieldType: string;\n count: number;\n /** Every answer, newest day first. */\n answers: { id: string; date: string; text: string }[];\n}\n\nexport type QuestionSummary = ScaleSummary | ChoiceSummary | TextSummary;\n\nconst CHOICE_TYPES: ReadonlySet<string> = new Set([\n \"single-choice\",\n \"multi-choice\",\n \"dropdown\",\n \"yes-no\",\n \"consent\",\n]);\nconst YES_NO = [\n { value: \"true\", label: \"Yes\" },\n { value: \"false\", label: \"No\" },\n];\nconst CONSENT = [\n { value: \"true\", label: \"Agreed\" },\n { value: \"false\", label: \"Didn't agree\" },\n];\n\n/** The summary row that counts a question's typed \"Other\" answers. */\nexport const OTHER_BUCKET = \"__other__\";\n\nconst optionsOf = (field: FieldBlock) =>\n field.type === \"yes-no\"\n ? YES_NO\n : field.type === \"consent\"\n ? CONSENT\n : choiceOptions(field).map((o) => ({ value: o.value, label: o.label ?? o.value }));\n\nconst ratingMax = (field: FieldBlock) => {\n const max = field.props?.[\"max\"];\n return typeof max === \"number\" && Number.isInteger(max) && max >= 1 && max <= 100 ? max : 5;\n};\n\n/** A rating or NPS question's own scale; null for other questions. */\nconst scaleOf = (field: FieldBlock): { min: number; max: number } | null =>\n field.type === \"nps\" ? { min: 0, max: 10 } : field.type === \"rating\" ? { min: 1, max: ratingMax(field) } : null;\n\nconst newestFirst = <T extends { date: string }>(items: readonly T[]) =>\n items\n .map((item, index) => ({ item, index }))\n .sort((x, y) =>\n x.item.date < y.item.date ? 1 : x.item.date > y.item.date ? -1 : x.index - y.index,\n )\n .map((x) => x.item);\n\n/**\n * One summary per question across `definitions` (newest first: it sets the order, labels,\n * type and options), counting each item's answers by field key. Keys in `skip` are left out.\n */\nexport function summarizeResponses(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): QuestionSummary[] {\n const newest = new Map<string, FieldBlock>();\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind === \"field\" && !newest.has(block.key)) newest.set(block.key, block);\n }\n }\n const answered = newestFirst(items).map((item) => ({\n item,\n values: valuesByKey(item.definition, item.answers),\n cells: answersByKey(item.definition, item.answers),\n }));\n\n return answerColumns(definitions, skip).flatMap((column): QuestionSummary[] => {\n const field = newest.get(column.key);\n if (!field) return [];\n const { key, label } = column;\n\n if (field.type === \"rating\" || field.type === \"nps\") {\n const nps = field.type === \"nps\";\n // The newest version sets the scale. One pass: a bucket array, never a spread of\n // every answer (that overflows the stack on large forms).\n const min = nps ? 0 : 1;\n const max = nps ? 10 : ratingMax(field);\n const counts = new Array<number>(max - min + 1).fill(0);\n let count = 0;\n let sum = 0;\n let promoters = 0;\n let detractors = 0;\n let rescaled = 0;\n let excluded = 0;\n for (const { values } of answered) {\n const answer = values.get(key);\n if (!answer) continue;\n const v = answer.value;\n const own = scaleOf(answer.field);\n if (!own || typeof v !== \"number\" || !Number.isInteger(v) || v < own.min || v > own.max) {\n excluded++;\n continue;\n }\n let x = v;\n if (own.min !== min || own.max !== max) {\n // Another version's scale: the same share of the way along this one.\n x = own.max === own.min ? max : min + ((v - own.min) * (max - min)) / (own.max - own.min);\n rescaled++;\n }\n const point = Math.round(x);\n counts[point - min]! += 1;\n count++;\n sum += x;\n if (point >= 9) promoters++;\n else if (point <= 6) detractors++;\n }\n return [\n {\n kind: \"scale\",\n key,\n label,\n type: field.type,\n fieldType: field.type,\n count,\n min,\n max,\n average: count ? sum / count : null,\n buckets: counts.map((c, i) => ({ value: min + i, count: c })),\n rescaled,\n excluded,\n nps:\n nps && count\n ? {\n promoters,\n passives: count - promoters - detractors,\n detractors,\n score: Math.round(((promoters - detractors) / count) * 100),\n }\n : null,\n },\n ];\n }\n\n if (CHOICE_TYPES.has(field.type)) {\n const options = optionsOf(field).map((o) => ({ ...o, count: 0 }));\n // Lookups by value, not options.find per answer: option lists can hold thousands.\n const byValue = new Map<string, (typeof options)[number]>();\n for (const o of options) if (!byValue.has(o.value)) byValue.set(o.value, o);\n const add = (option: (typeof options)[number]) => {\n options.push(option);\n byValue.set(option.value, option);\n return option;\n };\n const oldOptions = new Map<FieldBlock, Map<string, { label?: string }>>();\n const oldOption = (from: FieldBlock, value: string) => {\n let map = oldOptions.get(from);\n if (!map) {\n map = new Map();\n for (const o of optionsOf(from)) if (!map.has(o.value)) map.set(o.value, o);\n oldOptions.set(from, map);\n }\n return map.get(value);\n };\n const find = (value: string, from: FieldBlock) => {\n const known = byValue.get(value);\n if (known) return known;\n // Typed \"Other\" answers count together, under the question's Other label. (Checked only\n // for values not already counted: isOtherValue looks through the question's options.)\n if (isOtherValue(from, value)) {\n return (\n byValue.get(OTHER_BUCKET) ??\n add({ value: OTHER_BUCKET, label: (otherOption(field) ?? otherOption(from))!.label, count: 0 })\n );\n }\n // An option only an older version had: its label from that version.\n return add({ value, label: oldOption(from, value)?.label ?? value, count: 0 });\n };\n let count = 0;\n for (const { values } of answered) {\n const answer = values.get(key);\n if (!answer) continue;\n const chosen = (Array.isArray(answer.value) ? answer.value : [answer.value]).filter(\n (v): v is string | boolean => typeof v === \"string\" || typeof v === \"boolean\",\n );\n if (!chosen.length) continue;\n count++;\n for (const v of new Set(chosen.map(String))) find(v, answer.field).count++;\n }\n return [\n {\n kind: \"choice\",\n key,\n label,\n fieldType: field.type,\n count,\n multiple: field.type === \"multi-choice\",\n options: options.map((o) => ({ ...o, percent: count ? (o.count / count) * 100 : 0 })),\n },\n ];\n }\n\n const answers = answered.flatMap(({ item, cells }) => {\n const text = String(cells[key] ?? \"\").trim();\n return text ? [{ id: item.id, date: item.date, text }] : [];\n });\n return [{ kind: \"text\", key, label, fieldType: field.type, count: answers.length, answers }];\n });\n}\n\n/** The highest score any rating question in `definitions` asks for (NPS left out); null when none. */\nexport function highestRating(definitions: readonly FormDefinition[]): number | null {\n let max: number | null = null;\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind === \"field\" && block.type === \"rating\")\n max = Math.max(max ?? 0, ratingMax(block));\n }\n }\n return max;\n}\n\n/** The lowest rating-question answer in an item (NPS left out), or null when it has none. */\nexport function lowestRating(item: SummaryItem): number | null {\n let lowest: number | null = null;\n for (const { field, value } of valuesByKey(item.definition, item.answers).values()) {\n if (field.type === \"rating\" && typeof value === \"number\" && (lowest === null || value < lowest))\n lowest = value;\n }\n return lowest;\n}\n\n/** \"Low\" is the bottom 40% of a rating's scale: 2 or below out of 5, 4 or below out of 10. */\nconst LOW_SHARE = 0.4;\n/** NPS detractors: 0 to 6. */\nconst NPS_LOW = 6;\n\n/**\n * The highest answer that counts as low on a rating or NPS question: the bottom 40% of a\n * rating's scale (at least 1), or 0–6 (detractors) on NPS. Null for other questions.\n */\nexport function lowRatingAtMost(field: FieldBlock): number | null {\n if (field.type === \"nps\") return NPS_LOW;\n if (field.type !== \"rating\") return null;\n return lowScaleAtMost(\"rating\", ratingMax(field));\n}\n\n/** lowRatingAtMost for a scale known only by its type and top score (a ScaleSummary's). */\nexport function lowScaleAtMost(type: \"rating\" | \"nps\", max: number): number {\n return type === \"nps\" ? NPS_LOW : Math.max(1, Math.floor(max * LOW_SHARE));\n}\n\n/** Whether any rating or NPS answer in an item is low on its own question's scale. */\nexport function hasLowRating(item: SummaryItem): boolean {\n return hasLowRatingExcept(item, new Set());\n}\n\n/** hasLowRating, leaving out the answers to keys in `skip` (as summaries and needsFollowUp do). */\nexport function hasLowRatingExcept(item: SummaryItem, skip: ReadonlySet<string>): boolean {\n for (const [key, { field, value }] of valuesByKey(item.definition, item.answers)) {\n if (skip.has(key)) continue;\n const atMost = lowRatingAtMost(field);\n if (atMost !== null && typeof value === \"number\" && value <= atMost) return true;\n }\n return false;\n}\n\n/**\n * What \"low\" means across `definitions`, in words: \"2 or below\" for one 1–5 scale, \"2 or\n * below out of 5, 4 or below out of 10\" for two, \"0–6 on NPS\" beside them (\"0–6\" alone).\n * Null when no question has a rating or NPS answer.\n */\nexport function lowRatingLabel(definitions: readonly FormDefinition[]): string | null {\n const scales = new Set<number>();\n let nps = false;\n for (const definition of definitions) {\n for (const block of definition.blocks) {\n if (block.kind !== \"field\") continue;\n if (block.type === \"nps\") nps = true;\n else if (block.type === \"rating\") scales.add(ratingMax(block));\n }\n }\n const several = scales.size + (nps ? 1 : 0) > 1;\n const parts = [...scales]\n .sort((a, b) => a - b)\n .map((max) => {\n const atMost = Math.max(1, Math.floor(max * LOW_SHARE));\n return several ? `${atMost} or below out of ${max}` : `${atMost} or below`;\n });\n if (nps) parts.push(several ? `0–${NPS_LOW} on NPS` : `0–${NPS_LOW}`);\n return parts.length ? parts.join(\", \") : null;\n}\n\nexport interface ResponseFilter {\n /** First and last day, YYYY-MM-DD, both included; open-ended when absent. */\n from?: string | null;\n to?: string | null;\n /** Extra values that must match exactly, such as { class: \"6am WOD\" }. */\n match?: Record<string, string | null | undefined>;\n /** Only items with a rating at or below this (any rating question). */\n ratingAtMost?: number | null;\n /** Only items with a low answer on its question's own scale (hasLowRating). */\n low?: boolean;\n /** By status (matchesStatus); default `counted`: sent and partial, not in progress. */\n status?: StatusFilter | undefined;\n}\n\n/** Whether a filter leaves anything out beyond the default (in-progress responses). */\nexport function isFiltered(filter: ResponseFilter): boolean {\n return Boolean(\n filter.from ||\n filter.to ||\n filter.ratingAtMost != null ||\n filter.low ||\n (filter.status && filter.status !== \"counted\") ||\n Object.values(filter.match ?? {}).some((v) => v != null && v !== \"\"),\n );\n}\n\n/** The items a filter keeps, in their order. */\nexport function filterResponses<T extends SummaryItem>(\n items: readonly T[],\n filter: ResponseFilter,\n): T[] {\n const match = Object.entries(filter.match ?? {}).filter(\n (e): e is [string, string] => e[1] != null && e[1] !== \"\",\n );\n return items.filter((item) => {\n if (!matchesStatus(item, filter.status)) return false;\n if (filter.from && item.date < filter.from) return false;\n if (filter.to && item.date > filter.to) return false;\n if (match.some(([key, value]) => String(item.extra?.[key] ?? \"\") !== value)) return false;\n if (filter.ratingAtMost != null) {\n const lowest = lowestRating(item);\n if (lowest === null || lowest > filter.ratingAtMost) return false;\n }\n if (filter.low && !hasLowRating(item)) return false;\n return true;\n });\n}\n\nexport type DatePreset = \"all\" | \"today\" | \"week\" | \"7d\" | \"30d\" | \"month\";\n\nconst addDays = (day: string, n: number) => {\n const t = Date.parse(`${day}T00:00:00Z`) + n * 86_400_000;\n return new Date(t).toISOString().slice(0, 10);\n};\n\n/**\n * A preset's first and last day, given today (YYYY-MM-DD, on the clock the items' days\n * use). \"week\" starts on Monday; \"7d\" and \"30d\" include today.\n */\nexport function presetRange(\n preset: DatePreset,\n today: string,\n): { from: string | null; to: string | null } {\n switch (preset) {\n case \"all\":\n return { from: null, to: null };\n case \"today\":\n return { from: today, to: today };\n case \"week\": {\n const weekday = new Date(`${today}T00:00:00Z`).getUTCDay(); // 0 is Sunday\n return { from: addDays(today, -((weekday + 6) % 7)), to: today };\n }\n case \"7d\":\n return { from: addDays(today, -6), to: today };\n case \"30d\":\n return { from: addDays(today, -29), to: today };\n case \"month\":\n return { from: `${today.slice(0, 7)}-01`, to: today };\n }\n}\n\n// The filter bar ----------------------------------------------------------------------------\n\n/** What the filter bar holds; `toResponseFilter` turns it into a filter. */\nexport interface FiltersValue {\n when: DatePreset | \"custom\";\n /** Custom range, YYYY-MM-DD; empty for open-ended. */\n from: string;\n to: string;\n /** By choice filter key, e.g. { class: \"6am WOD\" }; missing or empty for any. */\n match: Record<string, string>;\n ratingAtMost: number | null;\n /** Low ratings, each on its own question's scale (lowRatingAtMost). */\n low: boolean;\n /** By status, on a form that saves answers as they go; missing is `counted`. */\n status?: StatusFilter | undefined;\n}\n\nexport const NO_FILTERS: FiltersValue = {\n when: \"all\",\n from: \"\",\n to: \"\",\n match: {},\n ratingAtMost: null,\n low: false,\n};\n\n/** The filter for `value`, given today's date on the clock the responses' days use. */\nexport function toResponseFilter(value: FiltersValue, today: string): ResponseFilter {\n const range =\n value.when === \"custom\"\n ? { from: value.from || null, to: value.to || null }\n : presetRange(value.when, today);\n return {\n ...range,\n match: value.match,\n ratingAtMost: value.ratingAtMost,\n low: value.low,\n ...(value.status ? { status: value.status } : {}),\n };\n}\n\n/**\n * The one-click \"Low ratings this week\": this week, and low on each question's own scale\n * (lowRatingAtMost: the bottom 40% of a rating, NPS detractors), other filters kept.\n */\nexport const lowThisWeek = (value: FiltersValue): FiltersValue => ({\n ...value,\n when: \"week\",\n low: true,\n});\n","// The Responses tab's headline numbers: how many responses (and the change against the\n// period before), the average of the form's main rating, how many have a low rating, and\n// the rate of the form's first consent or yes/no question. Built on summary.ts. Pure.\nimport type { FormDefinition } from \"@marktiderman/genesis-forms\";\nimport type { HeadlineNumber } from \"@marktiderman/genesis-ui/resource\";\nimport {\n hasLowRatingExcept,\n presetRange,\n summarizeResponses,\n type FiltersValue,\n type ResponseFilter,\n type SummaryItem,\n} from \"./summary\";\n\nexport interface Headline {\n responses: {\n count: number;\n /** Responses in the period before, under the same other filters; null with no period. */\n previous: number | null;\n /** count − previous; null with no period. */\n change: number | null;\n /** How many of `count` are partial (never sent); left out when there are none. */\n partial?: number;\n };\n /** The first rating question (newest definition order); null when the form has none. */\n rating: {\n key: string;\n label: string;\n max: number;\n /** Null when nobody answered it. */\n average: number | null;\n /** The same question's average in the period before; null without one or without answers. */\n previousAverage: number | null;\n /** average − previousAverage, when both are known. */\n change: number | null;\n } | null;\n /** Responses with a low answer on any rating or NPS question; null when there is none. */\n low: { count: number } | null;\n /** The first consent question, else the first yes/no one; null when there is none. */\n rate: {\n key: string;\n label: string;\n type: \"consent\" | \"yes-no\";\n /** Agreed or Yes. */\n yes: number;\n /** How many answered it. */\n count: number;\n /** 0–100; null when nobody answered. */\n percent: number | null;\n } | null;\n}\n\n/**\n * The headline numbers for `items` (already filtered), with `previous` (the same filters\n * over the period before, from `comparisonFilter`) for the changes. `definitions` are\n * newest first, as `summarizeResponses` takes them; `skip` leaves keys out.\n */\nexport function headlineNumbers(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n options: { previous?: readonly SummaryItem[] | null; skip?: ReadonlySet<string> } = {},\n): Headline {\n const previous = options.previous ?? null;\n const summaries = summarizeResponses(items, definitions, options.skip);\n const partial = items.filter((i) => i.status === \"partial\").length;\n const before = previous ? summarizeResponses(previous, definitions, options.skip) : null;\n\n const scale = summaries.find((s) => s.kind === \"scale\" && s.type === \"rating\");\n let rating: Headline[\"rating\"] = null;\n if (scale && scale.kind === \"scale\") {\n const old = before?.find((s) => s.kind === \"scale\" && s.key === scale.key);\n const previousAverage = old && old.kind === \"scale\" ? old.average : null;\n rating = {\n key: scale.key,\n label: scale.label,\n max: scale.max,\n average: scale.average,\n previousAverage,\n change:\n scale.average !== null && previousAverage !== null\n ? Math.round((scale.average - previousAverage) * 10) / 10\n : null,\n };\n }\n\n const scored = summaries.some((s) => s.kind === \"scale\");\n const choice =\n summaries.find((s) => s.kind === \"choice\" && s.fieldType === \"consent\") ??\n summaries.find((s) => s.kind === \"choice\" && s.fieldType === \"yes-no\");\n let rate: Headline[\"rate\"] = null;\n if (choice && choice.kind === \"choice\") {\n const yes = choice.options.find((o) => o.value === \"true\")?.count ?? 0;\n rate = {\n key: choice.key,\n label: choice.label,\n type: choice.fieldType as \"consent\" | \"yes-no\",\n yes,\n count: choice.count,\n percent: choice.count ? Math.round((yes / choice.count) * 100) : null,\n };\n }\n\n return {\n responses: {\n count: items.length,\n previous: previous ? previous.length : null,\n change: previous ? items.length - previous.length : null,\n ...(partial ? { partial } : {}),\n },\n rating,\n // The same skip as needsFollowUp, so the Low ratings card and the follow-up list agree.\n low: scored ? { count: items.filter((i) => hasLowRatingExcept(i, options.skip ?? new Set())).length } : null,\n rate,\n };\n}\n\nconst addDays = (day: string, n: number) =>\n new Date(Date.parse(`${day}T00:00:00Z`) + n * 86_400_000).toISOString().slice(0, 10);\nconst daysBetween = (from: string, to: string) =>\n Math.round((Date.parse(`${to}T00:00:00Z`) - Date.parse(`${from}T00:00:00Z`)) / 86_400_000);\n\n/**\n * The period before the one the filter bar picks, with the bar's other filters kept, and\n * what to call it (\"last week\"). \"This week\" compares with the same weekdays last week,\n * \"This month\" with last month up to the same day, any other range with as many days\n * just before it. Null for \"All time\", or a\n * custom range with an open end.\n */\nexport function comparisonFilter(\n value: FiltersValue,\n today: string,\n): { filter: ResponseFilter; label: string } | null {\n const range =\n value.when === \"custom\"\n ? { from: value.from || null, to: value.to || null }\n : presetRange(value.when, today);\n if (!range.from || !range.to || range.to < range.from) return null;\n let from: string;\n let to: string;\n if (value.when === \"month\") {\n const first = `${range.from.slice(0, 7)}-01`;\n const lastMonth = addDays(first, -1); // the last day of last month\n from = `${lastMonth.slice(0, 7)}-01`;\n const day = Math.min(Number(range.to.slice(8, 10)), Number(lastMonth.slice(8, 10)));\n to = `${lastMonth.slice(0, 7)}-${String(day).padStart(2, \"0\")}`;\n } else if (value.when === \"week\") {\n // Monday to today, against the same weekdays last week.\n from = addDays(range.from, -7);\n to = addDays(range.to, -7);\n } else {\n const length = daysBetween(range.from, range.to) + 1;\n to = addDays(range.from, -1);\n from = addDays(range.from, -length);\n }\n const label =\n value.when === \"today\"\n ? \"yesterday\"\n : value.when === \"week\"\n ? \"last week\"\n : value.when === \"month\"\n ? \"last month\"\n : value.when === \"7d\"\n ? \"the 7 days before\"\n : value.when === \"30d\"\n ? \"the 30 days before\"\n : \"the days before\";\n return {\n filter: {\n from,\n to,\n match: value.match,\n ratingAtMost: value.ratingAtMost,\n low: value.low,\n ...(value.status ? { status: value.status } : {}),\n },\n label,\n };\n}\n\nconst signed = (n: number, digits = 0) => {\n const s = Math.abs(n).toFixed(digits);\n return n > 0 ? `+${s}` : n < 0 ? `−${s}` : s;\n};\n\n/**\n * The cards for `headlineNumbers`' answer: Responses (with the change against `period`,\n * e.g. \"last week\"), Average rating, Low ratings, and the consent or yes/no rate. A card\n * the form has no question for is left out.\n */\nexport function headlineCards(\n headline: Headline,\n options: {\n period?: string | null | undefined;\n /** How many low-rated responses still need a follow-up (not handled); the card says so. */\n lowOpen?: number | undefined;\n } = {},\n): HeadlineNumber[] {\n const cards: HeadlineNumber[] = [];\n const { responses, rating, low, rate } = headline;\n // Partial responses count, and the card says how many there are.\n const partial = responses.partial ? `${responses.partial} partial` : null;\n cards.push({\n key: \"responses\",\n label: \"Responses\",\n value: responses.count,\n ...(responses.change !== null && options.period\n ? {\n detail:\n (responses.change === 0 ? `Same as ${options.period}` : `${signed(responses.change)} vs ${options.period}`) +\n (partial ? ` · ${partial}` : \"\"),\n tone: responses.change > 0 ? (\"positive\" as const) : responses.change < 0 ? (\"negative\" as const) : (\"muted\" as const),\n }\n : partial\n ? { detail: `Including ${partial}` }\n : {}),\n });\n if (rating) {\n const change = rating.change;\n cards.push({\n key: \"rating\",\n label: \"Average rating\",\n value: rating.average === null ? \"–\" : `${rating.average.toFixed(1)} / ${rating.max}`,\n ...(change !== null && options.period\n ? {\n detail: change === 0 ? `Same as ${options.period}` : `${change > 0 ? \"Up\" : \"Down\"} ${Math.abs(change).toFixed(1)}`,\n tone: change > 0 ? (\"positive\" as const) : change < 0 ? (\"warning\" as const) : (\"muted\" as const),\n }\n : rating.average === null\n ? { detail: \"No ratings yet\" }\n : {}),\n });\n }\n if (low) {\n const open = options.lowOpen ?? low.count;\n cards.push({\n key: \"low\",\n label: \"Low ratings\",\n value: low.count,\n ...(open\n ? { detail: open === 1 ? \"Needs a follow-up\" : `${open} need a follow-up`, tone: \"negative\" as const }\n : { detail: low.count ? \"All followed up\" : \"None\" }),\n });\n }\n if (rate) {\n cards.push({\n key: \"rate\",\n label: rate.label || (rate.type === \"consent\" ? \"Agreed\" : \"Yes\"),\n value: rate.percent === null ? \"–\" : `${rate.percent}%`,\n detail: rate.count\n ? `${rate.yes} of ${rate.count} ${rate.type === \"consent\" ? \"agreed\" : \"said yes\"}`\n : \"No answers yet\",\n });\n }\n return cards;\n}\n","// Drop-off by question (Typeform's \"question-by-question insights\"), for a form that saves\n// answers as they go: for each question, how many people reached it and how many stopped\n// there without sending. Worked out on each respondent's own path, rebuilt with genesis-forms\n// `computePath` from what a response keeps, and its furthest question. Pure.\nimport { computePath, type FieldBlock, type FormDefinition, type Json } from \"@marktiderman/genesis-forms\";\nimport { answerColumns } from \"./answers\";\nimport type { SummaryItem } from \"./summary\";\n\nexport interface QuestionDropOff {\n key: string;\n label: string;\n /** How many responses reached this question (it was on their path, on screen or answered). */\n views: number;\n /** How many stopped here: their furthest question, never sent. */\n stopped: number;\n /** stopped ÷ views as a whole percentage; null when nobody reached it. */\n dropOff: number | null;\n}\n\nexport interface DropOffSummary {\n /**\n * How many people started: distinct responses of any status (sent, partial, in progress),\n * each once. Someone is saved once they answer a question or move on from the first.\n */\n started: number;\n /** Each question's views and drop-off (`dropOffByQuestion`). */\n dropOffs: QuestionDropOff[];\n}\n\n/**\n * The field ids on a response's path, in order: genesis-forms `computePath` over its\n * `answers` (by field id), its `hidden` inputs and its `extraAnswers` (by field key).\n */\nfunction pathFields(item: SummaryItem): string[] {\n const { definition } = item;\n const fields = new Map<string, FieldBlock>();\n for (const block of definition.blocks) if (block.kind === \"field\") fields.set(block.id, block);\n const values: Record<string, Json | undefined> = { ...item.answers };\n if (item.extraAnswers) {\n for (const field of fields.values()) {\n const kept = Object.prototype.hasOwnProperty.call(item.extraAnswers, field.key)\n ? item.extraAnswers[field.key]\n : undefined;\n // A null in `answers` is a placeholder for a value kept apart: the extra one fills it.\n if (kept != null && values[field.id] == null) values[field.id] = kept;\n }\n }\n const { path } = computePath(definition, { values, hidden: item.hidden ?? {}, fields });\n return path.filter((id) => fields.has(id));\n}\n\n/**\n * Each question's views and drop-off, in the newest definition's order (`definitions`\n * newest first, as `summarizeResponses` takes them), matched across versions by field key.\n * Each response counts once (by `id`).\n *\n * - A sent response (`completed`, or no status) reached every question on its path and\n * stopped at none. A question logic hid or jumped over for them was never reached.\n * - A `partial` response reached the questions on its path before its `furthest` (the\n * path is rebuilt from the answers so far, so it can run past it), then `furthest`, and\n * stopped there. One without `furthest` (saved before it was kept) is left out.\n * - An `in_progress` response is left out: they may still be answering.\n *\n * The path is rebuilt from `answers`, `hidden` and `extraAnswers`; give the item every\n * answer logic can read, or a rule reading a missing one sees it unanswered. Two things a\n * stored response can't tell, so they count as on the path:\n *\n * - A question a prefilled link answered and hid (`props.prefill.hideWhenPrefilled`):\n * which answers came from the link lives in the form's answer events, which aren't kept.\n * - A rule comparing a pick from a host-supplied option list to an option value, when the\n * host stores the pick as its label: the rule sees the label.\n *\n * Someone who opened the form and left before moving on from the first question was\n * never saved, so they aren't counted.\n */\nexport function dropOffByQuestion(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): QuestionDropOff[] {\n const views = new Map<string, number>();\n const stopped = new Map<string, number>();\n const add = (map: Map<string, number>, key: string) => map.set(key, (map.get(key) ?? 0) + 1);\n const seen = new Set<string>();\n for (const item of items) {\n if (seen.has(item.id)) continue;\n seen.add(item.id);\n const status = item.status ?? \"completed\";\n if (status === \"in_progress\") continue;\n const keyOf = new Map<string, string>();\n const order = new Map<string, number>();\n item.definition.blocks.forEach((b, at) => {\n if (b.kind === \"field\") keyOf.set(b.id, b.key);\n order.set(b.id, at);\n });\n if (status === \"completed\") {\n for (const id of pathFields(item)) add(views, keyOf.get(id)!);\n continue;\n }\n const furthest = item.furthest ?? null;\n if (furthest === null || !keyOf.has(furthest)) continue;\n const at = order.get(furthest)!;\n for (const id of pathFields(item)) if (id !== furthest && order.get(id)! < at) add(views, keyOf.get(id)!);\n add(views, keyOf.get(furthest)!);\n add(stopped, keyOf.get(furthest)!);\n }\n return answerColumns(definitions, skip).map(({ key, label }) => {\n const reached = views.get(key) ?? 0;\n const left = stopped.get(key) ?? 0;\n return {\n key,\n label,\n views: reached,\n stopped: left,\n dropOff: reached ? Math.round((left / reached) * 100) : null,\n };\n });\n}\n\n/**\n * What `<DropOffByQuestion>` shows: how many people started and each question's drop-off.\n * Pass every response under the host's filters except status (in-progress ones count as\n * started, never per question).\n */\nexport function dropOffSummary(\n items: readonly SummaryItem[],\n definitions: readonly FormDefinition[],\n skip: ReadonlySet<string> = new Set(),\n): DropOffSummary {\n return {\n started: new Set(items.map((i) => i.id)).size,\n dropOffs: dropOffByQuestion(items, definitions, skip),\n };\n}\n","// Which responses need a follow-up (a low rating, not handled yet), with the low score\n// and the first written comment each one has. Pure.\nimport { answerCell, valuesByKey } from \"./answers\";\nimport { lowRatingAtMost, type SummaryItem } from \"./summary\";\n\nexport interface FollowUp<T extends SummaryItem = SummaryItem> {\n item: T;\n /** The lowest low answer, on its own question's scale. */\n rating: { value: number; max: number; type: \"rating\" | \"nps\" };\n /** The first written answer (short or long text), trimmed; null when there is none. */\n comment: string | null;\n}\n\nconst TEXT_TYPES: ReadonlySet<string> = new Set([\"long-text\", \"short-text\", \"text\"]);\n\nconst scaleMax = (type: string, props: Record<string, unknown> | undefined) =>\n type === \"nps\" ? 10 : typeof props?.[\"max\"] === \"number\" ? (props[\"max\"] as number) : 5;\n\n/** One item's follow-up, or null when none of its answers is low. */\nexport function followUpOf<T extends SummaryItem>(\n item: T,\n skip: ReadonlySet<string> = new Set(),\n): FollowUp<T> | null {\n let rating: FollowUp[\"rating\"] | null = null;\n let comment: string | null = null;\n for (const [key, { field, value }] of valuesByKey(item.definition, item.answers)) {\n if (skip.has(key)) continue;\n const atMost = lowRatingAtMost(field);\n if (atMost !== null && typeof value === \"number\" && value <= atMost) {\n const max = scaleMax(field.type, field.props);\n // The lowest share of its scale wins: a 2 of 5 is lower than a 4 of 10.\n if (!rating || value / max < rating.value / rating.max)\n rating = { value, max, type: field.type as \"rating\" | \"nps\" };\n } else if (comment === null && TEXT_TYPES.has(field.type)) {\n const text = String(answerCell(field, value)).trim();\n if (text) comment = text;\n }\n }\n return rating ? { item, rating, comment } : null;\n}\n\n/**\n * The items that need a follow-up, newest day first: a low answer on a rating or NPS\n * question (lowRatingAtMost), and not handled yet. `skip` leaves keys out (contact details).\n */\nexport function needsFollowUp<T extends SummaryItem>(\n items: readonly T[],\n options: { isHandled?: (item: T) => boolean; skip?: ReadonlySet<string> } = {},\n): FollowUp<T>[] {\n return items\n .map((item, index) => ({ index, f: options.isHandled?.(item) ? null : followUpOf(item, options.skip) }))\n .filter((x): x is { index: number; f: FollowUp<T> } => x.f !== null)\n .sort((x, y) =>\n x.f.item.date < y.f.item.date ? 1 : x.f.item.date > y.f.item.date ? -1 : x.index - y.index,\n )\n .map((x) => x.f);\n}\n","// Whether a form is taking responses, and if not why: the one rule every surface uses\n// (the public page and its submit endpoint, a forms list, the form's header and\n// settings). Generic form settings (status, opening and closing times, paused and a\n// response cap). Pure. Moved up from the host app's src/lib/forms/availability.ts; an app\n// that stores forms should apply the same rule on save.\n\nexport type FormAvailability =\n \"draft\" | \"archived\" | \"paused\" | \"scheduled\" | \"closed\" | \"full\" | \"live\";\n\nexport interface AvailabilityInput {\n status: \"draft\" | \"active\" | \"archived\";\n /** False when the form has never been published (it has no version to serve). */\n published?: boolean;\n /**\n * ISO times it takes responses from and until; open-ended when absent. Each needs `Z` or\n * an offset (`+02:00`): a time without one would be read on whatever clock the code runs\n * on. One that doesn't parse, or has no offset, keeps the form closed (fail closed).\n * Normalise times where they are written (`new Date(…).toISOString()`).\n */\n opensAt?: string | null | undefined;\n closesAt?: string | null | undefined;\n paused?: boolean | undefined;\n /** At most this many completed responses; null or absent for no cap. */\n responseCap?: number | null | undefined;\n /** Completed, non-deleted responses so far, when the caller knows the count. */\n completedResponses?: number | null | undefined;\n /** Whether the cap is reached, when only that is known (the public page never sees the count). */\n full?: boolean | undefined;\n}\n\n/** Whether the form has its response cap: from `full` when given, else from the cap and count. */\nexport function isFull(\n form: Pick<AvailabilityInput, \"responseCap\" | \"completedResponses\" | \"full\">,\n): boolean {\n if (form.full !== undefined) return form.full;\n return (\n form.responseCap != null &&\n form.completedResponses != null &&\n form.completedResponses >= form.responseCap\n );\n}\n\n// A date, a time, then Z or an hours-and-minutes offset.\nconst INSTANT = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\n/** An ISO time with `Z` or an offset, as epoch milliseconds; NaN for anything else. */\nexport function parseInstant(value: string): number {\n const v = value.trim();\n return INSTANT.test(v) ? Date.parse(v.replace(\" \", \"T\")) : Number.NaN;\n}\n\n/**\n * Where a form stands at `at`. Archived and draft first, then paused (staff chose it,\n * whatever the clock says), then the opening window (a time that can't be read, or has no\n * offset, counts as closed), then the cap. Only \"live\" takes\n * responses.\n */\nexport function formAvailability(form: AvailabilityInput, at: Date = new Date()): FormAvailability {\n if (form.status === \"archived\") return \"archived\";\n if (form.status === \"draft\" || form.published === false) return \"draft\";\n if (form.paused) return \"paused\";\n const t = at.getTime();\n if (form.opensAt) {\n const opens = parseInstant(form.opensAt);\n // A time that can't be read never opens the form.\n if (Number.isNaN(opens)) return \"closed\";\n if (t < opens) return \"scheduled\";\n }\n if (form.closesAt) {\n const closes = parseInstant(form.closesAt);\n if (Number.isNaN(closes) || t >= closes) return \"closed\";\n }\n if (isFull(form)) return \"full\";\n return \"live\";\n}\n\n/** Whether the form takes responses at `at`. */\nexport function takesResponses(form: AvailabilityInput, at: Date = new Date()): boolean {\n return formAvailability(form, at) === \"live\";\n}\n","// A form page's status chip and its four child navigation items with their counts. Pure.\nimport type { FormDefinition } from \"@marktiderman/genesis-forms\";\nimport type { FormAvailability } from \"./availability\";\nimport type { SubNavItem } from \"@marktiderman/genesis-ui/layout\";\nimport type { ChipTone } from \"@marktiderman/genesis-ui/resource/rules\";\n\n/**\n * A form's status chip: \"Live · version 3\", \"Draft\", \"Paused · version 3\"… `availability`\n * is formAvailability's answer; `version` the live version, when there is one.\n */\nexport function formStatusChip(\n availability: FormAvailability,\n version?: number | null,\n): { label: string; tone: ChipTone } {\n const v = version ? ` · version ${version}` : \"\";\n switch (availability) {\n case \"live\":\n return { label: `Live${v}`, tone: \"success\" };\n case \"draft\":\n return { label: \"Draft\", tone: \"muted\" };\n case \"paused\":\n return { label: `Paused${v}`, tone: \"warning\" };\n case \"scheduled\":\n return { label: `Scheduled${v}`, tone: \"info\" };\n case \"closed\":\n return { label: `Closed${v}`, tone: \"muted\" };\n case \"full\":\n return { label: `Full${v}`, tone: \"warning\" };\n case \"archived\":\n return { label: \"Archived\", tone: \"muted\" };\n }\n}\n\n/** The form page's four places, in order. */\nexport type FormTab = \"questions\" | \"logic\" | \"responses\" | \"settings\";\n\n/** One of a form page's child navigation items: genesis-ui's `SubNavItem`, plus its place. */\nexport type FormNavItem = SubNavItem & { id: FormTab; badge?: number };\n\n/** How many questions a definition asks, and how many rules plus endings it has. */\nexport function formCounts(definition: FormDefinition | null | undefined): {\n questions: number;\n logic: number;\n} {\n if (!definition) return { questions: 0, logic: 0 };\n return {\n questions: definition.blocks.filter((b) => b.kind === \"field\").length,\n logic: (definition.logic?.length ?? 0) + (definition.endings?.length ?? 0),\n };\n}\n\n/**\n * The form page's child navigation items (Questions, Logic and endings, Responses,\n * Settings) with their counts as badges, for the app shell's sub-navigation:\n * `useAppShellSubNav(formNavItems(\"/forms/f1\", counts))`. `at` is the form page's path\n * (each place is `?tab=<id>` on it, Questions the path itself, which the shell's most\n * specific match keeps from lighting up on the others) or a function giving each place's\n * address. A count left out (or null) shows no badge.\n */\nexport function formNavItems(\n at: string | ((tab: FormTab) => string),\n counts: { questions?: number | null; logic?: number | null; responses?: number | null } = {},\n /** Each place's icon, for the rail and the phone's bottom bar (`FORM_NAV_ICONS`). */\n icons?: Partial<Record<FormTab, SubNavItem[\"icon\"]>>,\n): FormNavItem[] {\n const to = typeof at === \"function\" ? at : (tab: FormTab) => (tab === \"questions\" ? at : `${at}?tab=${tab}`);\n const item = (id: FormTab, label: string, badge?: number | null): FormNavItem => {\n const icon = icons?.[id];\n return {\n id,\n to: to(id),\n label,\n ...(badge == null ? {} : { badge }),\n ...(icon ? { icon } : {}),\n };\n };\n return [\n item(\"questions\", \"Questions\", counts.questions),\n item(\"logic\", \"Logic and endings\", counts.logic),\n item(\"responses\", \"Responses\", counts.responses),\n item(\"settings\", \"Settings\"),\n ];\n}\n","// The pure half of the resource workspace moved to genesis-ui\n// (`@marktiderman/genesis-ui/resource/rules`). These names stay here, deprecated, so\n// existing imports keep working; the form's own words (an empty form says \"Add a\n// question\") are passed from here.\nimport {\n SAVE_STATE_LABEL as UI_SAVE_STATE_LABEL,\n dayLabel as uiDayLabel,\n embedSnippet as uiEmbedSnippet,\n prefilledUrl as uiPrefilledUrl,\n readinessChip as uiReadinessChip,\n readinessOf as uiReadinessOf,\n type ChipTone as UiChipTone,\n type PrefillChoice as UiPrefillChoice,\n type Readiness as UiReadiness,\n type ReadinessFinding,\n type ReadinessLabels,\n type ReadinessOptions,\n type SaveState as UiSaveState,\n} from \"@marktiderman/genesis-ui/resource/rules\";\n\n/** A form's readiness rule: the builder's `no-questions` finding means \"nothing to publish yet\". */\nexport const FORM_READINESS_OPTIONS = { emptyCode: \"no-questions\" } as const satisfies ReadinessOptions;\n\n/** A form's readiness words: an empty form says \"Add a question\". */\nexport const FORM_READINESS_LABELS = { empty: \"Add a question\" } as const satisfies ReadinessLabels;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type SaveState = UiSaveState;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type ChipTone = UiChipTone;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type Readiness = UiReadiness;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport type PrefillChoice = UiPrefillChoice;\n\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const SAVE_STATE_LABEL: Record<SaveState, string> = UI_SAVE_STATE_LABEL;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const dayLabel: typeof uiDayLabel = uiDayLabel;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const prefilledUrl: typeof uiPrefilledUrl = uiPrefilledUrl;\n/** @deprecated import from @marktiderman/genesis-ui */\nexport const embedSnippet: typeof uiEmbedSnippet = uiEmbedSnippet;\n\n/**\n * Readiness from a form builder's findings (`no-questions` is \"empty\").\n * @deprecated import from @marktiderman/genesis-ui: `readinessOf(findings, { ...FORM_READINESS_OPTIONS, pending })`\n */\nexport function readinessOf(\n findings: readonly ReadinessFinding[],\n options: ReadinessOptions = {},\n): Readiness {\n return uiReadinessOf(findings, { ...FORM_READINESS_OPTIONS, ...options });\n}\n\n/**\n * The readiness chip's label and tone, in a form's words.\n * @deprecated import from @marktiderman/genesis-ui: `readinessChip(readiness, FORM_READINESS_LABELS)`\n */\nexport function readinessChip(\n readiness: Readiness,\n labels: ReadinessLabels = {},\n): { label: string; tone: ChipTone } {\n return uiReadinessChip(readiness, { ...FORM_READINESS_LABELS, ...labels });\n}\n","// A form's public link and a duplicate's name: what a forms list needs to make a form or\n// copy one, without storage. Pure. Moved up from the host app's src/lib/feedback/admin.ts.\n\n/**\n * \"How was class?\" → \"how-was-class\": the public link's last part (lowercase words and\n * hyphens, at most 60). `fallback` is used when the title has no letters or numbers.\n */\nexport function slugFromTitle(title: string, fallback = \"form\"): string {\n const slug = title\n .toLowerCase()\n .normalize(\"NFKD\")\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60)\n .replace(/-+$/g, \"\");\n return slug || fallback;\n}\n\n/** A form link: lowercase letters and numbers, in words joined by single hyphens. */\nexport const SLUG_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;\n\n/** Why a form link can't be used, or nothing when it fits SLUG_PATTERN. */\nexport function validateSlug(slug: string): string | undefined {\n return SLUG_PATTERN.test(slug)\n ? undefined\n : \"Use lowercase letters, numbers and hyphens for the link, like how-was-class.\";\n}\n\n/** A duplicate's name: \"Copy of …\", within the 120 characters a form name may have. */\nexport function copyTitle(title: string): string {\n return `Copy of ${title}`.slice(0, 120);\n}\n\n/** The first of `slug`, `slug-2`, `slug-3`… that isn't in `taken`, within 60 characters. */\nexport function freeSlug(slug: string, taken: ReadonlySet<string>): string {\n if (!taken.has(slug)) return slug;\n for (let n = 2; ; n++) {\n const suffix = `-${n}`;\n const candidate = `${slug.slice(0, 60 - suffix.length).replace(/-+$/, \"\")}${suffix}`;\n if (!taken.has(candidate)) return candidate;\n }\n}\n","// What a respondent's thank-you page offers. Pure: safe in the browser bundle and in\n// tests. Moved up from the host app's src/lib/feedback/respondent.ts.\n\n/**\n * Whether the thank-you page offers \"Send another response\" (on unless `submitAnother`\n * is false). Never on a form that takes one response per person: a second response\n * would be refused. Anonymous forms don't know who answered, so one per person doesn't apply.\n */\nexport function offersSubmitAnother(form: {\n submitAnother?: boolean | null | undefined;\n onePerPerson?: boolean | null | undefined;\n anonymous?: boolean | null | undefined;\n}): boolean {\n const onePerPerson = form.onePerPerson === true && !form.anonymous;\n return form.submitAnother !== false && !onePerPerson;\n}\n"]}
|