Open each core value as a card of meaning and signals steps, so groups write their own words from an empty field with Generate draft, skip values without blocking the flow, and Customize without keeping helper text as the description.

This commit is contained in:
adilallo committed 2026-11-05 21:28:00 -07:00
1 parent 2a7b9e6da7
commit 64a542f456
25 files changed
+877 -354

No files matched your search

@@ -3,8 +3,7 @@
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import MultiSelect from "../../../../components/controls/MultiSelect";
import type { ChipOption } from "../../../../components/controls/MultiSelect/MultiSelect.types";
import Create from "../../../../components/modals/Create";
import ContentLockup from "../../../../components/type/ContentLockup";
import InlineTextButton from "../../../../components/buttons/InlineTextButton";
import { useMessages } from "../../../../contexts/MessagesContext";
import { buildCoreValueChipOptionsFromDraft } from "../../../../../lib/create/coreValueChipOptionsFromDraft";
import { useCreateFlow } from "../../context/CreateFlowContext";
@@ -16,8 +15,8 @@ import type {
} from "../../types";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowTwoColumnSelectShell } from "../../components/CreateFlowTwoColumnSelectShell";
import { CoreValueEditFields } from "../../components/methodEditFields";
import CustomMethodCardModalBody from "../../components/CustomMethodCardModalBody";
import { ValueDialog } from "../../components/ValueDialog";
import CustomMethodCardWizard from "../../components/CustomMethodCardWizard";
import { usesWizardFieldBlocksModalBody } from "../../../../../lib/create/usesWizardFieldBlocksModalBody";
import { buildCustomRuleModalKebabMenu } from "../../components/customRuleModalKebabMenu";
@@ -49,8 +48,8 @@ const MAX_CORE_VALUES = MAX_SELECTED_CORE_VALUES;
* - `editing` — chip already exists & is selected; modal reopened to
* tweak meaning/signals. Dismiss = no-op (chip stays as-is).
*
* **Add value** (and the header "add" link) opens an empty custom-policy
* wizard. Finalize writes a selected chip named from the wizard title.
* The header **add your own** link opens an empty custom-policy wizard.
* Finalize writes a selected chip named from the wizard title.
*/
type ModalSession = "pending" | "customPending" | "editing";
@@ -98,7 +97,7 @@ function chipOptionsToSnapshotRows(
const EMPTY_DETAIL: CoreValueDetailEntry = { meaning: "", signals: "" };
/** Create Custom — Core Values (Figma `20264:68378`). Up to six selections; preset list + custom chips. */
/** Create Custom — Core Values (Figma `20264:68378`). Overlay / Modal / Card `24973:1852`. Up to six selections; preset list + custom chips. */
export function CoreValuesSelectScreen() {
const m = useMessages();
const cv = m.create.customRule.coreValues;
@@ -448,8 +447,6 @@ export function CoreValuesSelectScreen() {
}),
);
const showFooterPrimary = Boolean(modalSession);
const handleCustomize = useCallback(() => {
if (!activeModalChipId) return;
markCreateFlowInteraction();
@@ -457,8 +454,7 @@ export function CoreValuesSelectScreen() {
buildMethodCardWizardInitialValues({
cardId: activeModalChipId,
fallbackTitle: modalChipLabel,
fallbackDescription:
draft.supportText?.trim() || cv.detailModal.subtitle,
fallbackDescription: draft.supportText?.trim() || "",
meta: {},
persistedBlocks: state.customMethodCardFieldBlocksById,
draftFieldBlocks,
@@ -478,7 +474,6 @@ export function CoreValuesSelectScreen() {
activeModalChipId,
cv.detailModal.meaningLabel,
cv.detailModal.signalsLabel,
cv.detailModal.subtitle,
draft,
draftFieldBlocks,
markCreateFlowInteraction,
@@ -606,15 +601,12 @@ export function CoreValuesSelectScreen() {
atSelectionLimit
? undefined
: handleDuplicateCoreChip,
showRemove: modalSession === "editing",
onRemove: handleRemoveFromKebab,
});
}, [
activeModalChipId,
atSelectionLimit,
handleCustomize,
handleDuplicateCoreChip,
handleRemoveFromKebab,
modalKebabMenu,
modalSession,
state.editingPublishedRuleId,
@@ -677,7 +669,7 @@ export function CoreValuesSelectScreen() {
queueMicrotask(() => {
syncCoreValuesToDraft(next);
// Both branches treat the chip as a brand-new draft until the
// user confirms via Add Value — dismissal removes it.
// user confirms via Add to Rule — dismissal removes it.
openModal(chipId, "customPending", value);
});
return next;
@@ -695,26 +687,17 @@ export function CoreValuesSelectScreen() {
const description = (
<>
<span className="leading-[1.3] text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
{cv.header.descriptionLead}{" "}
</span>
<button
type="button"
{cv.header.descriptionLead}
<InlineTextButton
onClick={addHandlers.onAddClick}
disabled={atSelectionLimit}
className="cursor-pointer font-normal leading-[1.3] text-[color:var(--color-content-default-tertiary,#b4b4b4)] underline decoration-solid underline-offset-[3px] hover:opacity-90 disabled:cursor-not-allowed disabled:no-underline disabled:opacity-60 disabled:hover:opacity-60"
>
{cv.header.addLink}
</button>
<span className="leading-[1.3] text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
{" "}
{cv.header.descriptionTrail}
</span>
</InlineTextButton>
{cv.header.descriptionTrail}
</>
);
const detailModal = cv.detailModal;
return (
<>
<CreateFlowTwoColumnSelectShell
@@ -735,75 +718,54 @@ export function CoreValuesSelectScreen() {
onAddClick={addHandlers.onAddClick}
onCustomChipConfirm={addHandlers.onCustomChipConfirm}
onCustomChipClose={addHandlers.onCustomChipClose}
addButton
addButtonText={cv.multiSelect.addButtonText}
addButton={false}
maxSelections={MAX_CORE_VALUES}
selectionCountText={selectionCountText}
limitReachedAnnouncement={cv.multiSelect.limitReached}
/>
{detailModal && (
<Create
isOpen={activeModalChipId !== null && !addCustomWizardOpen}
onClose={handleModalDismiss}
backdropVariant="blurredYellow"
headerContent={
<div className="bg-[var(--color-surface-default-primary)] px-[24px] py-[12px] shrink-0">
<ContentLockup
title={modalChipLabel}
description={
draft.supportText?.trim() || detailModal.subtitle
}
variant="modal"
alignment="left"
/>
</div>
}
showBackButton={false}
showNextButton={showFooterPrimary}
showRemoveButton={modalSession === "editing"}
onRemove={handleRemoveFromKebab}
onNext={handleModalConfirm}
nextButtonText={
modalSession === "editing"
? modalKebabMenu.saveEdits
: detailModal.addValueButton
}
kebabTriggerAriaLabel={modalKebabMenu.triggerAriaLabel}
kebabMenuAriaLabel={modalKebabMenu.menuAriaLabel}
kebabMenuItems={
kebabMenuItems.length > 0 ? kebabMenuItems : undefined
}
ariaLabel={modalChipLabel || "Core value details"}
>
{modalUsesWizardFieldBlocksBody && activeModalChipId ? (
<CustomMethodCardModalBody
cardId={activeModalChipId}
blocksById={state.customMethodCardFieldBlocksById}
blocksOverride={
draftFieldBlocks !== null ? draftFieldBlocks : undefined
}
showPolicyContentLockupWhenNoBlocks={false}
onFieldBlocksChange={
draftFieldBlocks === null
? undefined
: (next) => {
setDraftFieldBlocks(next);
setDraft(
coreValueDetailsFromWizardFieldBlocks(next, draft),
);
}
}
/>
) : (
<CoreValueEditFields
value={draft}
onChange={handleDraftChange}
generateDraft={getPresetTexts(modalChipLabel)}
/>
)}
</Create>
)}
<ValueDialog
isOpen={activeModalChipId !== null && !addCustomWizardOpen}
valueLabel={modalChipLabel}
session={modalSession === "editing" ? "editing" : "pending"}
draft={draft}
onDraftChange={handleDraftChange}
generateDraft={getPresetTexts(modalChipLabel)}
onClose={() => {
void handleModalDismiss();
}}
onConfirm={handleModalConfirm}
onDeselect={
modalSession === "editing" ? handleRemoveFromKebab : undefined
}
kebabTriggerAriaLabel={modalKebabMenu.triggerAriaLabel}
kebabMenuAriaLabel={modalKebabMenu.menuAriaLabel}
kebabMenuItems={
kebabMenuItems.length > 0 ? kebabMenuItems : undefined
}
ariaLabel={modalChipLabel || "Core value details"}
>
{modalUsesWizardFieldBlocksBody && activeModalChipId ? (
<CustomMethodCardModalBody
cardId={activeModalChipId}
blocksById={state.customMethodCardFieldBlocksById}
blocksOverride={
draftFieldBlocks !== null ? draftFieldBlocks : undefined
}
showPolicyContentLockupWhenNoBlocks={false}
onFieldBlocksChange={
draftFieldBlocks === null
? undefined
: (next) => {
setDraftFieldBlocks(next);
setDraft(
coreValueDetailsFromWizardFieldBlocks(next, draft),
);
}
}
/>
) : undefined}
</ValueDialog>
</CreateFlowTwoColumnSelectShell>
<CustomMethodCardWizard
isOpen={addCustomWizardOpen}