@multiplatform.one/components 7.28.1 → 7.29.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/cjs/Accordion/index.cjs +26 -17
- package/dist/cjs/Accordion/index.native.js +36 -27
- package/dist/cjs/Accordion/index.native.js.map +1 -1
- package/dist/cjs/Heading.cjs +74 -30
- package/dist/cjs/Heading.native.js +81 -30
- package/dist/cjs/Heading.native.js.map +1 -1
- package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
- package/dist/cjs/ScrollView/index.native.js +4 -0
- package/dist/cjs/ScrollView/index.native.js.map +1 -1
- package/dist/cjs/SortableList/SortableHandle.cjs +1 -1
- package/dist/cjs/SortableList/SortableHandle.native.js +1 -1
- package/dist/cjs/Text.cjs +58 -21
- package/dist/cjs/Text.native.js +62 -21
- package/dist/cjs/Text.native.js.map +1 -1
- package/dist/cjs/Toast/index.native.js.map +1 -1
- package/dist/cjs/charts/ChartDataView.cjs +2 -1
- package/dist/cjs/charts/ChartDataView.native.js +2 -1
- package/dist/cjs/charts/ChartDataView.native.js.map +1 -1
- package/dist/cjs/code/CodeBlock/index.cjs +8 -8
- package/dist/cjs/code/CodeBlock/index.native.js +8 -8
- package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.native.js +1 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/layouts/EmptyState.cjs +4 -3
- package/dist/cjs/layouts/EmptyState.native.js +14 -9
- package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
- package/dist/cjs/layouts/page.cjs +2 -1
- package/dist/cjs/layouts/page.native.js +2 -1
- package/dist/cjs/layouts/page.native.js.map +1 -1
- package/dist/cjs/layouts/sidebar.cjs +2 -1
- package/dist/cjs/layouts/sidebar.native.js +2 -1
- package/dist/cjs/layouts/sidebar.native.js.map +1 -1
- package/dist/cjs/layouts/tags.cjs +2 -1
- package/dist/cjs/layouts/tags.native.js +2 -1
- package/dist/cjs/layouts/tags.native.js.map +1 -1
- package/dist/cjs/layouts/toolbar.cjs +2 -1
- package/dist/cjs/layouts/toolbar.native.js +2 -1
- package/dist/cjs/layouts/toolbar.native.js.map +1 -1
- package/dist/cjs/shared/useReturnFocusOnClose.cjs +1 -0
- package/dist/cjs/shared/useReturnFocusOnClose.native.js +1 -0
- package/dist/cjs/shared/useReturnFocusOnClose.native.js.map +1 -1
- package/dist/cjs/surfaces.cjs +61 -0
- package/dist/cjs/surfaces.native.js +73 -0
- package/dist/cjs/surfaces.native.js.map +1 -1
- package/dist/cjs/views/Calendar.cjs +13 -10
- package/dist/cjs/views/Calendar.native.js +13 -10
- package/dist/cjs/views/Calendar.native.js.map +1 -1
- package/dist/cjs/views/Dashboard.cjs +2 -1
- package/dist/cjs/views/Dashboard.native.js +2 -1
- package/dist/cjs/views/Dashboard.native.js.map +1 -1
- package/dist/cjs/views/Gantt.cjs +39 -27
- package/dist/cjs/views/Gantt.native.js +38 -23
- package/dist/cjs/views/Gantt.native.js.map +1 -1
- package/dist/cjs/views/Kanban.cjs +2 -1
- package/dist/cjs/views/Kanban.native.js +1 -0
- package/dist/cjs/views/Kanban.native.js.map +1 -1
- package/dist/cjs/views/List.cjs +1 -0
- package/dist/cjs/views/List.native.js +1 -0
- package/dist/cjs/views/List.native.js.map +1 -1
- package/dist/cjs/views/Matrix.cjs +5 -3
- package/dist/cjs/views/Matrix.native.js +5 -3
- package/dist/cjs/views/Matrix.native.js.map +1 -1
- package/dist/cjs/views/ReportBuilder.cjs +2 -1
- package/dist/cjs/views/ReportBuilder.native.js +2 -1
- package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
- package/dist/cjs/views/TreeView.cjs +2 -1
- package/dist/cjs/views/TreeView.native.js +2 -1
- package/dist/cjs/views/TreeView.native.js.map +1 -1
- package/dist/esm/Accordion/index.mjs +26 -18
- package/dist/esm/Accordion/index.mjs.map +1 -1
- package/dist/esm/Accordion/index.native.js +36 -28
- package/dist/esm/Accordion/index.native.js.map +1 -1
- package/dist/esm/Heading.mjs +74 -30
- package/dist/esm/Heading.mjs.map +1 -1
- package/dist/esm/Heading.native.js +81 -30
- package/dist/esm/Heading.native.js.map +1 -1
- package/dist/esm/ProgressSteps/index.mjs.map +1 -1
- package/dist/esm/ProgressSteps/index.native.js.map +1 -1
- package/dist/esm/ScrollView/index.native.js +4 -0
- package/dist/esm/ScrollView/index.native.js.map +1 -1
- package/dist/esm/SortableList/SortableHandle.mjs +1 -1
- package/dist/esm/SortableList/SortableHandle.native.js +1 -1
- package/dist/esm/SortableList/SortableHandle.native.js.map +1 -1
- package/dist/esm/Text.mjs +58 -21
- package/dist/esm/Text.mjs.map +1 -1
- package/dist/esm/Text.native.js +62 -21
- package/dist/esm/Text.native.js.map +1 -1
- package/dist/esm/Toast/index.mjs.map +1 -1
- package/dist/esm/Toast/index.native.js.map +1 -1
- package/dist/esm/charts/ChartDataView.mjs +2 -1
- package/dist/esm/charts/ChartDataView.mjs.map +1 -1
- package/dist/esm/charts/ChartDataView.native.js +2 -1
- package/dist/esm/charts/ChartDataView.native.js.map +1 -1
- package/dist/esm/code/CodeBlock/index.mjs +1 -1
- package/dist/esm/code/CodeBlock/index.native.js +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +2 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/layouts/EmptyState.mjs +4 -3
- package/dist/esm/layouts/EmptyState.mjs.map +1 -1
- package/dist/esm/layouts/EmptyState.native.js +14 -9
- package/dist/esm/layouts/EmptyState.native.js.map +1 -1
- package/dist/esm/layouts/page.mjs +2 -1
- package/dist/esm/layouts/page.mjs.map +1 -1
- package/dist/esm/layouts/page.native.js +2 -1
- package/dist/esm/layouts/page.native.js.map +1 -1
- package/dist/esm/layouts/sidebar.mjs +2 -1
- package/dist/esm/layouts/sidebar.mjs.map +1 -1
- package/dist/esm/layouts/sidebar.native.js +2 -1
- package/dist/esm/layouts/sidebar.native.js.map +1 -1
- package/dist/esm/layouts/tags.mjs +2 -1
- package/dist/esm/layouts/tags.mjs.map +1 -1
- package/dist/esm/layouts/tags.native.js +2 -1
- package/dist/esm/layouts/tags.native.js.map +1 -1
- package/dist/esm/layouts/toolbar.mjs +2 -1
- package/dist/esm/layouts/toolbar.mjs.map +1 -1
- package/dist/esm/layouts/toolbar.native.js +2 -1
- package/dist/esm/layouts/toolbar.native.js.map +1 -1
- package/dist/esm/shared/useReturnFocusOnClose.mjs +1 -0
- package/dist/esm/shared/useReturnFocusOnClose.mjs.map +1 -1
- package/dist/esm/shared/useReturnFocusOnClose.native.js +1 -0
- package/dist/esm/shared/useReturnFocusOnClose.native.js.map +1 -1
- package/dist/esm/surfaces.mjs +63 -3
- package/dist/esm/surfaces.mjs.map +1 -1
- package/dist/esm/surfaces.native.js +75 -3
- package/dist/esm/surfaces.native.js.map +1 -1
- package/dist/esm/views/Calendar.mjs +12 -9
- package/dist/esm/views/Calendar.mjs.map +1 -1
- package/dist/esm/views/Calendar.native.js +12 -9
- package/dist/esm/views/Calendar.native.js.map +1 -1
- package/dist/esm/views/Dashboard.mjs +2 -1
- package/dist/esm/views/Dashboard.mjs.map +1 -1
- package/dist/esm/views/Dashboard.native.js +2 -1
- package/dist/esm/views/Dashboard.native.js.map +1 -1
- package/dist/esm/views/Gantt.mjs +37 -25
- package/dist/esm/views/Gantt.mjs.map +1 -1
- package/dist/esm/views/Gantt.native.js +36 -21
- package/dist/esm/views/Gantt.native.js.map +1 -1
- package/dist/esm/views/Kanban.mjs +2 -1
- package/dist/esm/views/Kanban.mjs.map +1 -1
- package/dist/esm/views/Kanban.native.js +1 -0
- package/dist/esm/views/Kanban.native.js.map +1 -1
- package/dist/esm/views/List.mjs +1 -0
- package/dist/esm/views/List.mjs.map +1 -1
- package/dist/esm/views/List.native.js +1 -0
- package/dist/esm/views/List.native.js.map +1 -1
- package/dist/esm/views/Matrix.mjs +3 -1
- package/dist/esm/views/Matrix.mjs.map +1 -1
- package/dist/esm/views/Matrix.native.js +3 -1
- package/dist/esm/views/Matrix.native.js.map +1 -1
- package/dist/esm/views/ReportBuilder.mjs +2 -1
- package/dist/esm/views/ReportBuilder.mjs.map +1 -1
- package/dist/esm/views/ReportBuilder.native.js +2 -1
- package/dist/esm/views/ReportBuilder.native.js.map +1 -1
- package/dist/esm/views/TreeView.mjs +2 -1
- package/dist/esm/views/TreeView.mjs.map +1 -1
- package/dist/esm/views/TreeView.native.js +2 -1
- package/dist/esm/views/TreeView.native.js.map +1 -1
- package/dist/jsx/Accordion/index.mjs +26 -18
- package/dist/jsx/Accordion/index.mjs.map +1 -1
- package/dist/jsx/Accordion/index.native.js +36 -27
- package/dist/jsx/Accordion/index.native.js.map +1 -1
- package/dist/jsx/Heading.mjs +74 -30
- package/dist/jsx/Heading.mjs.map +1 -1
- package/dist/jsx/Heading.native.js +81 -30
- package/dist/jsx/Heading.native.js.map +1 -1
- package/dist/jsx/ProgressSteps/index.mjs.map +1 -1
- package/dist/jsx/ProgressSteps/index.native.js.map +1 -1
- package/dist/jsx/ScrollView/index.native.js +4 -0
- package/dist/jsx/ScrollView/index.native.js.map +1 -1
- package/dist/jsx/SortableList/SortableHandle.mjs +1 -1
- package/dist/jsx/SortableList/SortableHandle.native.js +1 -1
- package/dist/jsx/Text.mjs +58 -21
- package/dist/jsx/Text.mjs.map +1 -1
- package/dist/jsx/Text.native.js +62 -21
- package/dist/jsx/Text.native.js.map +1 -1
- package/dist/jsx/Toast/index.mjs.map +1 -1
- package/dist/jsx/Toast/index.native.js.map +1 -1
- package/dist/jsx/charts/ChartDataView.mjs +2 -1
- package/dist/jsx/charts/ChartDataView.mjs.map +1 -1
- package/dist/jsx/charts/ChartDataView.native.js +2 -1
- package/dist/jsx/charts/ChartDataView.native.js.map +1 -1
- package/dist/jsx/code/CodeBlock/index.mjs +1 -1
- package/dist/jsx/code/CodeBlock/index.native.js +8 -8
- package/dist/jsx/code/CodeBlock/index.native.js.map +1 -1
- package/dist/jsx/index.js +2 -2
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +2 -2
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +1 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/layouts/EmptyState.mjs +4 -3
- package/dist/jsx/layouts/EmptyState.mjs.map +1 -1
- package/dist/jsx/layouts/EmptyState.native.js +14 -9
- package/dist/jsx/layouts/EmptyState.native.js.map +1 -1
- package/dist/jsx/layouts/page.mjs +2 -1
- package/dist/jsx/layouts/page.mjs.map +1 -1
- package/dist/jsx/layouts/page.native.js +2 -1
- package/dist/jsx/layouts/page.native.js.map +1 -1
- package/dist/jsx/layouts/sidebar.mjs +2 -1
- package/dist/jsx/layouts/sidebar.mjs.map +1 -1
- package/dist/jsx/layouts/sidebar.native.js +2 -1
- package/dist/jsx/layouts/sidebar.native.js.map +1 -1
- package/dist/jsx/layouts/tags.mjs +2 -1
- package/dist/jsx/layouts/tags.mjs.map +1 -1
- package/dist/jsx/layouts/tags.native.js +2 -1
- package/dist/jsx/layouts/tags.native.js.map +1 -1
- package/dist/jsx/layouts/toolbar.mjs +2 -1
- package/dist/jsx/layouts/toolbar.mjs.map +1 -1
- package/dist/jsx/layouts/toolbar.native.js +2 -1
- package/dist/jsx/layouts/toolbar.native.js.map +1 -1
- package/dist/jsx/shared/useReturnFocusOnClose.mjs +1 -0
- package/dist/jsx/shared/useReturnFocusOnClose.mjs.map +1 -1
- package/dist/jsx/shared/useReturnFocusOnClose.native.js +1 -0
- package/dist/jsx/shared/useReturnFocusOnClose.native.js.map +1 -1
- package/dist/jsx/surfaces.mjs +63 -3
- package/dist/jsx/surfaces.mjs.map +1 -1
- package/dist/jsx/surfaces.native.js +73 -0
- package/dist/jsx/surfaces.native.js.map +1 -1
- package/dist/jsx/views/Calendar.mjs +12 -9
- package/dist/jsx/views/Calendar.mjs.map +1 -1
- package/dist/jsx/views/Calendar.native.js +13 -10
- package/dist/jsx/views/Calendar.native.js.map +1 -1
- package/dist/jsx/views/Dashboard.mjs +2 -1
- package/dist/jsx/views/Dashboard.mjs.map +1 -1
- package/dist/jsx/views/Dashboard.native.js +2 -1
- package/dist/jsx/views/Dashboard.native.js.map +1 -1
- package/dist/jsx/views/Gantt.mjs +37 -25
- package/dist/jsx/views/Gantt.mjs.map +1 -1
- package/dist/jsx/views/Gantt.native.js +38 -23
- package/dist/jsx/views/Gantt.native.js.map +1 -1
- package/dist/jsx/views/Kanban.mjs +2 -1
- package/dist/jsx/views/Kanban.mjs.map +1 -1
- package/dist/jsx/views/Kanban.native.js +1 -0
- package/dist/jsx/views/Kanban.native.js.map +1 -1
- package/dist/jsx/views/List.mjs +1 -0
- package/dist/jsx/views/List.mjs.map +1 -1
- package/dist/jsx/views/List.native.js +1 -0
- package/dist/jsx/views/List.native.js.map +1 -1
- package/dist/jsx/views/Matrix.mjs +3 -1
- package/dist/jsx/views/Matrix.mjs.map +1 -1
- package/dist/jsx/views/Matrix.native.js +5 -3
- package/dist/jsx/views/Matrix.native.js.map +1 -1
- package/dist/jsx/views/ReportBuilder.mjs +2 -1
- package/dist/jsx/views/ReportBuilder.mjs.map +1 -1
- package/dist/jsx/views/ReportBuilder.native.js +2 -1
- package/dist/jsx/views/ReportBuilder.native.js.map +1 -1
- package/dist/jsx/views/TreeView.mjs +2 -1
- package/dist/jsx/views/TreeView.mjs.map +1 -1
- package/dist/jsx/views/TreeView.native.js +2 -1
- package/dist/jsx/views/TreeView.native.js.map +1 -1
- package/package.json +9 -9
- package/src/Accordion/index.tsx +34 -15
- package/src/Heading.stories.tsx +13 -0
- package/src/Heading.tsx +62 -21
- package/src/ProgressSteps/ProgressSteps.spec.tsx +2 -3
- package/src/ProgressSteps/index.tsx +3 -4
- package/src/ScrollView/ScrollView.native.spec.tsx +97 -1
- package/src/ScrollView/index.native.tsx +4 -0
- package/src/SortableList/SortableHandle.tsx +2 -2
- package/src/Tabs/Tabs.lifecycle.spec.tsx +3 -1
- package/src/Text.tsx +32 -20
- package/src/Toast/index.tsx +4 -3
- package/src/charts/ChartDataView.tsx +2 -1
- package/src/code/CodeBlock/index.tsx +1 -1
- package/src/feedback/ConfirmDialog.spec.tsx +2 -2
- package/src/icons/phosphorTokenColor.spec.tsx +86 -0
- package/src/index.ts +1 -1
- package/src/layouts/EmptyState.spec.tsx +17 -0
- package/src/layouts/EmptyState.tsx +10 -3
- package/src/layouts/Screen.keyboardTaps.spec.tsx +57 -0
- package/src/layouts/Screen.stories.tsx +55 -2
- package/src/layouts/page.tsx +2 -14
- package/src/layouts/sidebar.tsx +2 -1
- package/src/layouts/tags.tsx +1 -1
- package/src/layouts/toolbar.tsx +2 -1
- package/src/shared/useReturnFocusOnClose.spec.tsx +39 -0
- package/src/shared/useReturnFocusOnClose.ts +4 -0
- package/src/surfaces.spec.tsx +272 -3
- package/src/surfaces.tsx +97 -4
- package/src/textWeight.houseFonts.spec.tsx +127 -0
- package/src/textWeight.native.spec.tsx +27 -0
- package/src/textWeight.spec.tsx +15 -0
- package/src/views/Calendar.tsx +37 -29
- package/src/views/Dashboard.tsx +2 -13
- package/src/views/Gantt.scroll.spec.tsx +4 -1
- package/src/views/Gantt.tsx +40 -25
- package/src/views/Kanban.native.tsx +1 -0
- package/src/views/Kanban.tsx +2 -10
- package/src/views/List.tsx +1 -0
- package/src/views/Matrix.tsx +3 -1
- package/src/views/ReportBuilder.tsx +2 -1
- package/src/views/TreeView.tsx +2 -1
- package/src/views/views.spec.tsx +14 -2
- package/types/Accordion/index.d.ts +8 -0
- package/types/Accordion/index.d.ts.map +1 -1
- package/types/Chip/index.d.ts +1 -1
- package/types/Heading.d.ts +7 -7
- package/types/Heading.d.ts.map +1 -1
- package/types/ProgressSteps/index.d.ts.map +1 -1
- package/types/ScrollView/index.native.d.ts.map +1 -1
- package/types/SortableList/SortableHandle.d.ts +1 -1
- package/types/Tabs/index.d.ts +1 -1
- package/types/Text.d.ts +4 -4
- package/types/Text.d.ts.map +1 -1
- package/types/Toast/index.d.ts.map +1 -1
- package/types/charts/ChartDataView.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/layouts/EmptyState.d.ts.map +1 -1
- package/types/layouts/page.d.ts.map +1 -1
- package/types/layouts/sidebar.d.ts.map +1 -1
- package/types/layouts/tags.d.ts.map +1 -1
- package/types/layouts/toolbar.d.ts.map +1 -1
- package/types/shared/useReturnFocusOnClose.d.ts.map +1 -1
- package/types/surfaces.d.ts +14 -0
- package/types/surfaces.d.ts.map +1 -1
- package/types/views/Calendar.d.ts +18 -1
- package/types/views/Calendar.d.ts.map +1 -1
- package/types/views/Dashboard.d.ts.map +1 -1
- package/types/views/Gantt.d.ts.map +1 -1
- package/types/views/Kanban.d.ts.map +1 -1
- package/types/views/List.d.ts.map +1 -1
- package/types/views/Matrix.d.ts.map +1 -1
- package/types/views/ReportBuilder.d.ts.map +1 -1
- package/types/views/TreeView.d.ts.map +1 -1
package/src/Accordion/index.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
stackEdgeRadius,
|
|
12
12
|
useAccentTintedSurface,
|
|
13
13
|
useGroupPosition,
|
|
14
|
+
useLegibleInkOn,
|
|
14
15
|
useReadableTextOn,
|
|
15
16
|
useResolvedKnobs,
|
|
16
17
|
wasKeyboardFocus,
|
|
@@ -165,6 +166,20 @@ const AccordionItemCtx = createContext<AccordionItemCtxValue>({
|
|
|
165
166
|
position: "only",
|
|
166
167
|
});
|
|
167
168
|
|
|
169
|
+
/** The fill an open trigger paints under its title (the accent tint). */
|
|
170
|
+
const AccordionTriggerFillCtx = createContext<string | undefined>(undefined);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Ink for a title node a consumer renders inside `Accordion.Trigger`:
|
|
174
|
+
* `preferred` while it clears AA on the open trigger's fill, the fill's
|
|
175
|
+
* readable anchor where it does not (a muted `$color11` title on the dark
|
|
176
|
+
* accent tint measured 4.05:1, MPO-448). Bare string titles already get this
|
|
177
|
+
* from the trigger.
|
|
178
|
+
*/
|
|
179
|
+
export function useAccordionTriggerInk(preferred: string): string {
|
|
180
|
+
return useLegibleInkOn(useContext(AccordionTriggerFillCtx), preferred);
|
|
181
|
+
}
|
|
182
|
+
|
|
168
183
|
function useAccordionKnobs() {
|
|
169
184
|
const { compact, size } = useContext(AccordionCtx);
|
|
170
185
|
return useResolvedKnobs({ component: "Accordion", compact, size });
|
|
@@ -490,9 +505,11 @@ const AccordionTrigger = forwardRef<TamaguiElement, AccordionTriggerProps>(
|
|
|
490
505
|
: item.open && onSelectedTint
|
|
491
506
|
? onSelectedTint
|
|
492
507
|
: componentColors.text.primary;
|
|
493
|
-
const
|
|
494
|
-
?
|
|
495
|
-
|
|
508
|
+
const openDescriptionInk = useLegibleInkOn(
|
|
509
|
+
item.open ? selectedTint : undefined,
|
|
510
|
+
knobProps.textAccentColor,
|
|
511
|
+
);
|
|
512
|
+
const descriptionColor = item.disabled ? disabledState.textKnobProps.color : openDescriptionInk;
|
|
496
513
|
const visualPx = tokenPx(knobProps.sizeToken, MIN_PRESS_TARGET, "size");
|
|
497
514
|
const chevronPx = tokenPx(
|
|
498
515
|
knobProps.label.fontSize,
|
|
@@ -568,24 +585,26 @@ const AccordionTrigger = forwardRef<TamaguiElement, AccordionTriggerProps>(
|
|
|
568
585
|
{icon}
|
|
569
586
|
</View>
|
|
570
587
|
) : null}
|
|
571
|
-
<
|
|
572
|
-
{
|
|
588
|
+
<AccordionTriggerFillCtx.Provider value={item.open ? selectedTint : undefined}>
|
|
589
|
+
<YStack flex={1} minWidth={0} alignItems="flex-start">
|
|
590
|
+
{/* LC-82 TEXT-RIDES-TEXT: wrap ALL bare string/number children
|
|
573
591
|
(coalesced runs), not just the singleton case. */}
|
|
574
|
-
|
|
592
|
+
{/* Label weight rides the fontWeight knob (400 / 700). Never 500
|
|
575
593
|
or 600 — those are not house label weights (§6.1 / R7 text-node
|
|
576
594
|
trap). Selected state is fill (LC-71), not a heavier weight. */}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
{label}
|
|
580
|
-
</Text>
|
|
581
|
-
))}
|
|
582
|
-
{description != null &&
|
|
583
|
-
wrapBareTextChildren(description, (label, key) => (
|
|
584
|
-
<Text key={key} {...knobProps.label} textAlign="left" color={descriptionColor}>
|
|
595
|
+
{wrapBareTextChildren(children, (label, key) => (
|
|
596
|
+
<Text key={key} {...knobProps.label} textAlign="left" color={titleColor}>
|
|
585
597
|
{label}
|
|
586
598
|
</Text>
|
|
587
599
|
))}
|
|
588
|
-
|
|
600
|
+
{description != null &&
|
|
601
|
+
wrapBareTextChildren(description, (label, key) => (
|
|
602
|
+
<Text key={key} {...knobProps.label} textAlign="left" color={descriptionColor}>
|
|
603
|
+
{label}
|
|
604
|
+
</Text>
|
|
605
|
+
))}
|
|
606
|
+
</YStack>
|
|
607
|
+
</AccordionTriggerFillCtx.Provider>
|
|
589
608
|
</TamaguiAccordion.Trigger>
|
|
590
609
|
</View>
|
|
591
610
|
);
|
package/src/Heading.stories.tsx
CHANGED
|
@@ -69,3 +69,16 @@ export const FontWeightFlip: Story = {
|
|
|
69
69
|
</YStack>
|
|
70
70
|
),
|
|
71
71
|
};
|
|
72
|
+
|
|
73
|
+
export const SizedHeadings: Story = {
|
|
74
|
+
name: "Sized headings",
|
|
75
|
+
render: () => (
|
|
76
|
+
<YStack gap="$3" maxWidth={640}>
|
|
77
|
+
<H2 size="$6">H2 at $6: weight follows fontWeight in every headingFont</H2>
|
|
78
|
+
<Heading size="$4">Heading at $4</Heading>
|
|
79
|
+
<H2 size="$6" fontWeight="700">
|
|
80
|
+
H2 at $6 with an explicit 700
|
|
81
|
+
</H2>
|
|
82
|
+
</YStack>
|
|
83
|
+
),
|
|
84
|
+
};
|
package/src/Heading.tsx
CHANGED
|
@@ -41,39 +41,80 @@ import {
|
|
|
41
41
|
|
|
42
42
|
export type { HeadingProps };
|
|
43
43
|
|
|
44
|
-
/** Subordinate heading voice
|
|
45
|
-
const
|
|
44
|
+
/** Subordinate heading voice: mono, weight 400. Consumer props still eject. */
|
|
45
|
+
const SUBORDINATE_FAMILY = "$mono";
|
|
46
|
+
const SUBORDINATE_WEIGHT = "400";
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
type Weight = HeadingProps["fontWeight"];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The heading fragment without its weight, and the weight a heading writes
|
|
52
|
+
* as its last prop, so neither a `size` nor a `fontFamily` variant can paint
|
|
53
|
+
* the font ramp's weight over it (MPO-446, ./Text.tsx WEIGHT RIDES LAST).
|
|
54
|
+
* That ramp is why a sized heading swapped to `headingFont: serif` fell from
|
|
55
|
+
* Inter's 600 to the category font's 400.
|
|
56
|
+
*/
|
|
57
|
+
function useHeadingVoice(fontWeight: Weight) {
|
|
48
58
|
const { knobProps } = useResolvedKnobs();
|
|
49
|
-
|
|
59
|
+
const { fontWeight: knobWeight, ...heading } = knobProps.heading;
|
|
60
|
+
return {
|
|
61
|
+
heading,
|
|
62
|
+
pageTitle: knobProps.pageTitle,
|
|
63
|
+
weight: fontWeight ?? (knobWeight as Weight),
|
|
64
|
+
};
|
|
50
65
|
}
|
|
51
66
|
|
|
52
|
-
export function
|
|
53
|
-
const {
|
|
54
|
-
|
|
55
|
-
// heading-weight token). heading.fontWeight must land AFTER that so
|
|
56
|
-
// regular/bold reach the TEXT NODE instead of being swallowed.
|
|
57
|
-
return <RawH1 {...knobProps.pageTitle} {...knobProps.heading} {...props} />;
|
|
67
|
+
export function Heading({ fontWeight, ...props }: HeadingProps) {
|
|
68
|
+
const { heading, weight } = useHeadingVoice(fontWeight);
|
|
69
|
+
return <RawHeading {...heading} {...props} fontWeight={weight} />;
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
export function
|
|
61
|
-
const {
|
|
62
|
-
return <
|
|
72
|
+
export function H1({ fontWeight, ...props }: HeadingProps) {
|
|
73
|
+
const { heading, pageTitle, weight } = useHeadingVoice(fontWeight);
|
|
74
|
+
return <RawH1 {...pageTitle} {...heading} {...props} fontWeight={weight} />;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function H2({ fontWeight, ...props }: HeadingProps) {
|
|
78
|
+
const { heading, weight } = useHeadingVoice(fontWeight);
|
|
79
|
+
return <RawH2 {...heading} {...props} fontWeight={weight} />;
|
|
63
80
|
}
|
|
64
81
|
|
|
65
|
-
export function H3(props: HeadingProps) {
|
|
66
|
-
return
|
|
82
|
+
export function H3({ fontWeight, ...props }: HeadingProps) {
|
|
83
|
+
return (
|
|
84
|
+
<RawH3
|
|
85
|
+
fontFamily={SUBORDINATE_FAMILY}
|
|
86
|
+
{...props}
|
|
87
|
+
fontWeight={fontWeight ?? SUBORDINATE_WEIGHT}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
67
90
|
}
|
|
68
91
|
|
|
69
|
-
export function H4(props: HeadingProps) {
|
|
70
|
-
return
|
|
92
|
+
export function H4({ fontWeight, ...props }: HeadingProps) {
|
|
93
|
+
return (
|
|
94
|
+
<RawH4
|
|
95
|
+
fontFamily={SUBORDINATE_FAMILY}
|
|
96
|
+
{...props}
|
|
97
|
+
fontWeight={fontWeight ?? SUBORDINATE_WEIGHT}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
71
100
|
}
|
|
72
101
|
|
|
73
|
-
export function H5(props: HeadingProps) {
|
|
74
|
-
return
|
|
102
|
+
export function H5({ fontWeight, ...props }: HeadingProps) {
|
|
103
|
+
return (
|
|
104
|
+
<RawH5
|
|
105
|
+
fontFamily={SUBORDINATE_FAMILY}
|
|
106
|
+
{...props}
|
|
107
|
+
fontWeight={fontWeight ?? SUBORDINATE_WEIGHT}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
75
110
|
}
|
|
76
111
|
|
|
77
|
-
export function H6(props: HeadingProps) {
|
|
78
|
-
return
|
|
112
|
+
export function H6({ fontWeight, ...props }: HeadingProps) {
|
|
113
|
+
return (
|
|
114
|
+
<RawH6
|
|
115
|
+
fontFamily={SUBORDINATE_FAMILY}
|
|
116
|
+
{...props}
|
|
117
|
+
fontWeight={fontWeight ?? SUBORDINATE_WEIGHT}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
79
120
|
}
|
|
@@ -52,7 +52,7 @@ describe("ProgressSteps", () => {
|
|
|
52
52
|
expect(current.className).toContain("_bg-accentBackg");
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
it("
|
|
55
|
+
it("keeps the dark current fill on $accentBackground now the build holds it to 4.5 (MPO-448)", () => {
|
|
56
56
|
const { container } = render(
|
|
57
57
|
<TamaguiProvider config={houseConfig} defaultTheme="dark" disableInjectCSS>
|
|
58
58
|
<ProgressSteps steps={steps} current={1} />
|
|
@@ -60,8 +60,7 @@ describe("ProgressSteps", () => {
|
|
|
60
60
|
);
|
|
61
61
|
const current = container.querySelector('[aria-current="step"]') as HTMLElement;
|
|
62
62
|
expect(current).toBeTruthy();
|
|
63
|
-
expect(current.className).
|
|
64
|
-
expect(current.className).not.toContain("_bg-accentBackg");
|
|
63
|
+
expect(current.className).toContain("_bg-accentBackg");
|
|
65
64
|
});
|
|
66
65
|
|
|
67
66
|
it("calls onStepChange when jumping back to a completed step", () => {
|
|
@@ -158,10 +158,9 @@ export function ProgressSteps({
|
|
|
158
158
|
if (isWeb) ensureKeyboardModalityTracking();
|
|
159
159
|
const [kbFocusIndex, setKbFocusIndex] = useState<number | null>(null);
|
|
160
160
|
// LC-05: current marker rides an accent solid; completed/error fills pick
|
|
161
|
-
// paper/ink from luminance rather than an assumed white glyph.
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
// the nearest accent solid that can carry the numeral.
|
|
161
|
+
// paper/ink from luminance rather than an assumed white glyph. An
|
|
162
|
+
// `$accentBackground` under the 4.5 text floor against both scheme anchors
|
|
163
|
+
// walks to the nearest accent solid that can carry the numeral.
|
|
165
164
|
const currentFill = useAaSolidFill(componentColors.indicator.selected);
|
|
166
165
|
const onSelected = useReadableTextOn(currentFill);
|
|
167
166
|
const onCompleted = useReadableTextOn(componentColors.indicator.completed);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* ../../tests/nativeTamagui.ts); vitest's usual web build keeps onScroll and
|
|
5
5
|
* would pass with or without the fix.
|
|
6
6
|
*/
|
|
7
|
-
import { readdirSync, readFileSync } from "node:fs";
|
|
7
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
8
8
|
import { join, relative } from "node:path";
|
|
9
9
|
import { act, createElement, createRef } from "react";
|
|
10
10
|
import { createRoot, type Root } from "react-dom/client";
|
|
@@ -78,6 +78,35 @@ describe("tamagui native ScrollView (upstream control)", () => {
|
|
|
78
78
|
expect(host.onContentSizeChange).toBe(props.onContentSizeChange);
|
|
79
79
|
expect(host.onScroll).toBeUndefined();
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
it("leaves keyboardShouldPersistTaps unset, so RN falls back to never", () => {
|
|
83
|
+
const host = render(createElement(runtime.RawScrollView as AnyScrollView, { testID: "probe" }));
|
|
84
|
+
expect(host.keyboardShouldPersistTaps).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("components ScrollView keyboard taps on native (MPO-457)", () => {
|
|
89
|
+
it("hands keyboardShouldPersistTaps=handled to the RN ScrollView by default", () => {
|
|
90
|
+
const host = render(createElement(ScrollView as unknown as AnyScrollView, { testID: "probe" }));
|
|
91
|
+
expect(host.keyboardShouldPersistTaps).toBe("handled");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("keeps the default through a styled() extension", () => {
|
|
95
|
+
const Extended = styled(ScrollView, { name: "Extended" });
|
|
96
|
+
const host = render(createElement(Extended as unknown as AnyScrollView, { testID: "probe" }));
|
|
97
|
+
expect(host.keyboardShouldPersistTaps).toBe("handled");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("lets a consumer value win", () => {
|
|
101
|
+
for (const value of ["never", "always"]) {
|
|
102
|
+
const host = render(
|
|
103
|
+
createElement(ScrollView as unknown as AnyScrollView, { keyboardShouldPersistTaps: value }),
|
|
104
|
+
);
|
|
105
|
+
expect(host.keyboardShouldPersistTaps).toBe(value);
|
|
106
|
+
act(() => root.unmount());
|
|
107
|
+
container.remove();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
81
110
|
});
|
|
82
111
|
|
|
83
112
|
describe("components ScrollView on native", () => {
|
|
@@ -137,6 +166,35 @@ describe("catalog onScroll consumers", () => {
|
|
|
137
166
|
});
|
|
138
167
|
});
|
|
139
168
|
|
|
169
|
+
describe("catalog scroll owners (MPO-457)", () => {
|
|
170
|
+
it("take the components ScrollView, or declare keyboardShouldPersistTaps", () => {
|
|
171
|
+
const publicDir = join(import.meta.dirname, "../../..");
|
|
172
|
+
const house = join(import.meta.dirname, "index.native.tsx");
|
|
173
|
+
const raw: Array<[binding: string, from: string]> = [
|
|
174
|
+
["ScrollView", "tamagui"],
|
|
175
|
+
["ScrollView", "react-native"],
|
|
176
|
+
["FlashList", "@shopify/flash-list"],
|
|
177
|
+
];
|
|
178
|
+
const offenders = readdirSync(publicDir, { withFileTypes: true })
|
|
179
|
+
.filter((entry) => entry.isDirectory())
|
|
180
|
+
.flatMap((entry) => {
|
|
181
|
+
const src = join(publicDir, entry.name, "src");
|
|
182
|
+
return existsSync(src) ? sourceFiles(src) : [];
|
|
183
|
+
})
|
|
184
|
+
.filter((file) => file !== house)
|
|
185
|
+
.flatMap((file) => {
|
|
186
|
+
const code = readFileSync(file, "utf8");
|
|
187
|
+
return raw
|
|
188
|
+
.flatMap(([name, from]) => importedAs(code, name, from))
|
|
189
|
+
.flatMap((local) => [local, ...aliasesOf(code, local)])
|
|
190
|
+
.flatMap((local) => openingTags(code, local))
|
|
191
|
+
.filter((tag) => !/\bkeyboardShouldPersistTaps\b/.test(tag.text))
|
|
192
|
+
.map((tag) => `${relative(publicDir, file)}:${tag.line}`);
|
|
193
|
+
});
|
|
194
|
+
expect(offenders).toEqual([]);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
140
198
|
function sourceFiles(dir: string): string[] {
|
|
141
199
|
const out: string[] = [];
|
|
142
200
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -155,3 +213,41 @@ function importsScrollView(code: string, from: string): boolean {
|
|
|
155
213
|
match[1]!.split(",").some((part) => /^ScrollView\b/.test(part.trim())),
|
|
156
214
|
);
|
|
157
215
|
}
|
|
216
|
+
|
|
217
|
+
/** Local names a value import of `name` from `from` binds. */
|
|
218
|
+
function importedAs(code: string, name: string, from: string): string[] {
|
|
219
|
+
const re = new RegExp(`import\\s+\\{([^}]*)\\}\\s+from\\s+["']${from}["']`, "g");
|
|
220
|
+
const alias = new RegExp(`^${name}(?:\\s+as\\s+(\\w+))?$`);
|
|
221
|
+
return [...code.matchAll(re)].flatMap((match) =>
|
|
222
|
+
match[1]!.split(",").flatMap((part) => {
|
|
223
|
+
const found = part.trim().match(alias);
|
|
224
|
+
return found ? [found[1] ?? name] : [];
|
|
225
|
+
}),
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Consts that pick `local`, e.g. `const Scroller = isWeb ? ScrollView : RNScrollView`. */
|
|
230
|
+
function aliasesOf(code: string, local: string): string[] {
|
|
231
|
+
const re = new RegExp(`const\\s+(\\w+)\\s*=[^;\\n]*\\b${local}\\b`, "g");
|
|
232
|
+
return [...code.matchAll(re)].map((match) => match[1]!);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Every JSX opening tag of `name`, props included, with its line. */
|
|
236
|
+
function openingTags(code: string, name: string): Array<{ text: string; line: number }> {
|
|
237
|
+
const out: Array<{ text: string; line: number }> = [];
|
|
238
|
+
for (const match of code.matchAll(new RegExp(`<${name}(?![\\w.])`, "g"))) {
|
|
239
|
+
let depth = 0;
|
|
240
|
+
let end = match.index + match[0].length;
|
|
241
|
+
for (; end < code.length; end++) {
|
|
242
|
+
const char = code[end];
|
|
243
|
+
if (char === "{") depth++;
|
|
244
|
+
else if (char === "}") depth--;
|
|
245
|
+
else if (char === ">" && depth === 0) break;
|
|
246
|
+
}
|
|
247
|
+
out.push({
|
|
248
|
+
text: code.slice(match.index, end + 1),
|
|
249
|
+
line: code.slice(0, match.index).split("\n").length,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
@@ -27,6 +27,10 @@ const ScrollFrame = styled(
|
|
|
27
27
|
{
|
|
28
28
|
name: "ScrollView",
|
|
29
29
|
scrollEnabled: true,
|
|
30
|
+
// MPO-457: at RN's "never" a ScrollView claims, in the capture phase, the
|
|
31
|
+
// first tap on any descendant while the keyboard is up, and a native
|
|
32
|
+
// sheet's rows are React descendants of the screen that opened it.
|
|
33
|
+
keyboardShouldPersistTaps: "handled",
|
|
30
34
|
variants: {
|
|
31
35
|
fullscreen: {
|
|
32
36
|
true: { position: "absolute", inset: 0 },
|
|
@@ -27,7 +27,7 @@ export interface SortableHandleProps {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Leading grab handle: nested well, 16px 6-dot grip, opacity .
|
|
30
|
+
* Leading grab handle: nested well, 16px 6-dot grip, opacity .6 → 1.
|
|
31
31
|
* Focusable (W1-focus-ring): 2px ring, offset 0. Keyboard path can also
|
|
32
32
|
* live on the row — this control is tabIndex 0 so tables have a target
|
|
33
33
|
* that is not an in-cell editor.
|
|
@@ -58,7 +58,7 @@ export function SortableHandle({
|
|
|
58
58
|
minHeight={well}
|
|
59
59
|
alignItems="center"
|
|
60
60
|
justifyContent="center"
|
|
61
|
-
opacity={isDragging ? 1 : 0.
|
|
61
|
+
opacity={isDragging ? 1 : 0.6}
|
|
62
62
|
hoverStyle={{ opacity: 1 }}
|
|
63
63
|
{...({
|
|
64
64
|
tag: "button",
|
|
@@ -18,7 +18,9 @@ vi.mock("tamagui", async (original) => {
|
|
|
18
18
|
const observers: ControlledResizeObserver[] = [];
|
|
19
19
|
class ControlledResizeObserver {
|
|
20
20
|
elements = new Set<Element>();
|
|
21
|
-
|
|
21
|
+
readonly callback: ResizeObserverCallback;
|
|
22
|
+
constructor(callback: ResizeObserverCallback) {
|
|
23
|
+
this.callback = callback;
|
|
22
24
|
observers.push(this);
|
|
23
25
|
}
|
|
24
26
|
observe(element: Element) {
|
package/src/Text.tsx
CHANGED
|
@@ -18,6 +18,14 @@
|
|
|
18
18
|
* — the text node itself carries fontFamily/fontWeight/color on every
|
|
19
19
|
* platform (the MPO-44/48 lesson: the frame is not the text node).
|
|
20
20
|
*
|
|
21
|
+
* WEIGHT RIDES LAST (MPO-446). `size` and `fontFamily` are variants on the
|
|
22
|
+
* raw primitive, and tamagui's getFontSized writes the font ramp's weight
|
|
23
|
+
* (`var(--f-weight-N)`) at the position that key holds in the props object.
|
|
24
|
+
* A knob weight spread before a consumer `size` lost to it, and a consumer
|
|
25
|
+
* `fontWeight` sat at the knob's position too, since a spread key keeps its
|
|
26
|
+
* first slot. So the weight is split off the fragment and written as the
|
|
27
|
+
* final prop: the knob's, or the consumer's when one is passed.
|
|
28
|
+
*
|
|
21
29
|
* Knob channels wired here:
|
|
22
30
|
* - bodyFont → knobProps.body.fontFamily (every platform, not just web)
|
|
23
31
|
* - fontWeight → knobProps.body.fontWeight (regular 400 / bold 700 —
|
|
@@ -55,32 +63,36 @@ export type { AnchorProps, ParagraphProps, SizableTextProps, TextProps };
|
|
|
55
63
|
/** Measured $4 label ramp — Inter 14/25, weight from the fontWeight knob. */
|
|
56
64
|
const LABEL_RAMP = { fontSize: 14, lineHeight: 25 } as const;
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
type Weight = TextProps["fontWeight"];
|
|
67
|
+
|
|
68
|
+
/** The body fragment without its weight, and the weight a voice writes last. */
|
|
69
|
+
function useBodyVoice(fontWeight: Weight) {
|
|
59
70
|
const { knobProps } = useResolvedKnobs();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
const { fontWeight: knobWeight, ...body } = knobProps.body;
|
|
72
|
+
return {
|
|
73
|
+
body,
|
|
74
|
+
color: knobProps.textAccentColor,
|
|
75
|
+
weight: fontWeight ?? (knobWeight as Weight),
|
|
76
|
+
};
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
export function
|
|
66
|
-
const {
|
|
67
|
-
return <
|
|
79
|
+
export function Text({ fontWeight, ...props }: TextProps) {
|
|
80
|
+
const { body, color, weight } = useBodyVoice(fontWeight);
|
|
81
|
+
return <RawText {...LABEL_RAMP} {...body} color={color} {...props} fontWeight={weight} />;
|
|
68
82
|
}
|
|
69
83
|
|
|
70
|
-
export function
|
|
71
|
-
const {
|
|
72
|
-
return
|
|
73
|
-
<RawParagraph
|
|
74
|
-
{...LABEL_RAMP}
|
|
75
|
-
{...knobProps.body}
|
|
76
|
-
color={knobProps.textAccentColor}
|
|
77
|
-
{...props}
|
|
78
|
-
/>
|
|
79
|
-
);
|
|
84
|
+
export function SizableText({ fontWeight, ...props }: SizableTextProps) {
|
|
85
|
+
const { body, color, weight } = useBodyVoice(fontWeight);
|
|
86
|
+
return <RawSizableText {...body} color={color} {...props} fontWeight={weight} />;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
export function
|
|
83
|
-
const {
|
|
89
|
+
export function Paragraph({ fontWeight, ...props }: ParagraphProps) {
|
|
90
|
+
const { body, color, weight } = useBodyVoice(fontWeight);
|
|
91
|
+
return <RawParagraph {...LABEL_RAMP} {...body} color={color} {...props} fontWeight={weight} />;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function Anchor({ fontWeight, ...props }: AnchorProps) {
|
|
95
|
+
const { body, weight } = useBodyVoice(fontWeight);
|
|
84
96
|
const linkInk = useAccentOnSurface();
|
|
85
|
-
return <RawAnchor {...
|
|
97
|
+
return <RawAnchor {...body} color={linkInk} {...props} fontWeight={weight} />;
|
|
86
98
|
}
|
package/src/Toast/index.tsx
CHANGED
|
@@ -364,9 +364,10 @@ function useToastVisuals(intent: ToastIntent, compact?: boolean) {
|
|
|
364
364
|
const isAccent = intent === "accent";
|
|
365
365
|
// Semantic hues: step 11 — lowest AA-safe step of the hue on the step-1/2
|
|
366
366
|
// surface (resolves to a CSS var on web, concrete value on native).
|
|
367
|
-
// Accent
|
|
368
|
-
//
|
|
369
|
-
// step that still clears AA
|
|
367
|
+
// Accent glyphs ride $accentColor, which the build holds to 4.5:1 on the
|
|
368
|
+
// page surfaces in both schemes (MPO-449). The action label takes
|
|
369
|
+
// useAccentOnSurface: the most chromatic accent step that still clears AA
|
|
370
|
+
// 4.5:1 on color1/color2 (R7 / MPO-48).
|
|
370
371
|
const iconColor = (isAccent ? theme.accentColor?.get() : theme.color11?.get()) as
|
|
371
372
|
| string
|
|
372
373
|
| undefined;
|
|
@@ -2,7 +2,8 @@ import { Button } from "@multiplatform.one/forms";
|
|
|
2
2
|
import { isWeb } from "@multiplatform.one/platform";
|
|
3
3
|
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
4
4
|
import { createContext, useContext, useId, useState, type ReactNode } from "react";
|
|
5
|
-
import { Dialog, Paragraph,
|
|
5
|
+
import { Dialog, Paragraph, XStack, YStack } from "tamagui";
|
|
6
|
+
import { ScrollView } from "../ScrollView";
|
|
6
7
|
import { sectionHeading } from "../componentColors";
|
|
7
8
|
import { useTranslation } from "../shared/i18n";
|
|
8
9
|
import { DialogContent, DialogOverlay } from "../surfaces";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { useEffect, useRef, useState } from "react";
|
|
20
20
|
import { useTranslation } from "../../shared/i18n";
|
|
21
21
|
import type { TamaguiElement } from "tamagui";
|
|
22
|
-
import { ScrollView } from "
|
|
22
|
+
import { ScrollView } from "../../ScrollView";
|
|
23
23
|
import { Button, Input, zIndex } from "@multiplatform.one/forms";
|
|
24
24
|
import { Spacer, XStack, YStack } from "tamagui";
|
|
25
25
|
import { settleMs } from "../../AnimateHeight";
|
|
@@ -31,7 +31,7 @@ function alertdialog(): Element | null {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
describe("ConfirmDialog", () => {
|
|
34
|
-
it("
|
|
34
|
+
it("inks a disabled destructive label on the error hue's $color12 text step (LC-40)", () => {
|
|
35
35
|
renderWithProviders(
|
|
36
36
|
<ConfirmDialog
|
|
37
37
|
open
|
|
@@ -47,7 +47,7 @@ describe("ConfirmDialog", () => {
|
|
|
47
47
|
(node) => node.textContent === "Delete",
|
|
48
48
|
);
|
|
49
49
|
expect(label).toBeTruthy();
|
|
50
|
-
expect(label?.className).toContain("_col-
|
|
50
|
+
expect(label?.className).toContain("_col-color12");
|
|
51
51
|
expect(label?.className).toContain("_fow-400");
|
|
52
52
|
});
|
|
53
53
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-450. A phosphor glyph handed a Tamagui token paints that token's colour
|
|
3
|
+
* on web. Raw @phosphor-icons/react writes `color` straight into `<svg fill>`;
|
|
4
|
+
* "$color9" is not a paint, the browser drops it and the glyph falls back to
|
|
5
|
+
* black. createVitestConfig carries the same IconBase resolution every web
|
|
6
|
+
* bundle gets (phosphorTokenColorPlugin), so these renders go through it.
|
|
7
|
+
*/
|
|
8
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
9
|
+
import { FolderIcon, HeartIcon } from "@phosphor-icons/react";
|
|
10
|
+
import { Theme, useTheme } from "tamagui";
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
|
|
13
|
+
function ThemeValue({ name }: { name: string }) {
|
|
14
|
+
const theme = useTheme() as unknown as Record<string, { val?: unknown } | undefined>;
|
|
15
|
+
return <span data-theme-value={name} data-val={String(theme[name]?.val ?? "")} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function fillOf(container: HTMLElement, testId: string) {
|
|
19
|
+
return container.querySelector(`[data-testid="${testId}"]`)?.getAttribute("fill") ?? "";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function valueOf(container: HTMLElement, name: string) {
|
|
23
|
+
return container.querySelector(`[data-theme-value="${name}"]`)?.getAttribute("data-val") ?? "";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("phosphor glyph token colour on web (MPO-450)", () => {
|
|
27
|
+
it("paints $color9 with the theme's resolved colour, not the token string", () => {
|
|
28
|
+
const { container } = renderWithProviders(
|
|
29
|
+
<>
|
|
30
|
+
<FolderIcon data-testid="glyph" color="$color9" />
|
|
31
|
+
<ThemeValue name="color9" />
|
|
32
|
+
</>,
|
|
33
|
+
);
|
|
34
|
+
const fill = fillOf(container, "glyph");
|
|
35
|
+
expect(valueOf(container, "color9")).not.toBe("");
|
|
36
|
+
expect(fill).toBe(valueOf(container, "color9"));
|
|
37
|
+
expect(fill.startsWith("$")).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("resolves against the theme in scope, so dark paints the dark step", () => {
|
|
41
|
+
const { container } = renderWithProviders(
|
|
42
|
+
<>
|
|
43
|
+
<HeartIcon data-testid="light" color="$color11" />
|
|
44
|
+
<Theme name="dark">
|
|
45
|
+
<HeartIcon data-testid="dark" color="$color11" />
|
|
46
|
+
<ThemeValue name="color11" />
|
|
47
|
+
</Theme>
|
|
48
|
+
</>,
|
|
49
|
+
);
|
|
50
|
+
const dark = fillOf(container, "dark");
|
|
51
|
+
expect(dark).toBe(valueOf(container, "color11"));
|
|
52
|
+
expect(dark).not.toBe(fillOf(container, "light"));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("resolves a palette token such as the liked heart's $red11", () => {
|
|
56
|
+
const { container } = renderWithProviders(
|
|
57
|
+
<>
|
|
58
|
+
<HeartIcon data-testid="glyph" weight="fill" color="$red11" />
|
|
59
|
+
<ThemeValue name="red11" />
|
|
60
|
+
</>,
|
|
61
|
+
);
|
|
62
|
+
expect(valueOf(container, "red11")).not.toBe("");
|
|
63
|
+
expect(fillOf(container, "glyph")).toBe(valueOf(container, "red11"));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("leaves a literal colour alone", () => {
|
|
67
|
+
const { container } = renderWithProviders(<HeartIcon data-testid="glyph" color="#123456" />);
|
|
68
|
+
expect(fillOf(container, "glyph")).toBe("#123456");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("inherits currentColor when no colour is given", () => {
|
|
72
|
+
const { container } = renderWithProviders(<HeartIcon data-testid="glyph" />);
|
|
73
|
+
expect(fillOf(container, "glyph")).toBe("currentColor");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("takes the theme's ink, never black, for a token the theme does not carry", () => {
|
|
77
|
+
const { container } = renderWithProviders(
|
|
78
|
+
<>
|
|
79
|
+
<HeartIcon data-testid="glyph" color="$notAThemeKey" />
|
|
80
|
+
<ThemeValue name="color" />
|
|
81
|
+
</>,
|
|
82
|
+
);
|
|
83
|
+
expect(valueOf(container, "color")).not.toBe("");
|
|
84
|
+
expect(fillOf(container, "glyph")).toBe(valueOf(container, "color"));
|
|
85
|
+
});
|
|
86
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -51,7 +51,7 @@ export type { WizardFormLike, WizardProps, WizardStatus, WizardStep } from "./Wi
|
|
|
51
51
|
export { unwrapText } from "./utils/unwrapText";
|
|
52
52
|
export { Pagination, getPaginationItems } from "./Pagination";
|
|
53
53
|
export type { PaginationProps, PaginationItem } from "./Pagination";
|
|
54
|
-
export { Accordion } from "./Accordion";
|
|
54
|
+
export { Accordion, useAccordionTriggerInk } from "./Accordion";
|
|
55
55
|
export type {
|
|
56
56
|
AccordionProps,
|
|
57
57
|
AccordionVariant,
|
|
@@ -41,6 +41,23 @@ describe("EmptyState", () => {
|
|
|
41
41
|
expect(container.querySelector("h2")?.textContent).toBe("Create your first record");
|
|
42
42
|
expect(container.textContent).toContain("Records you add will show up here.");
|
|
43
43
|
});
|
|
44
|
+
|
|
45
|
+
// MPO-473: a refusal's server reason arrives as one message per line. One
|
|
46
|
+
// web paragraph collapsed the break, so the lines read as a single sentence.
|
|
47
|
+
it("renders each line of the description as its own paragraph", () => {
|
|
48
|
+
const { container } = renderWithProviders(
|
|
49
|
+
<EmptyState
|
|
50
|
+
title="You can't create Pokemon"
|
|
51
|
+
description={
|
|
52
|
+
"You are not permitted to access this resource. Login to access\nFunction frappe.desk.form.load.getdoctype is not whitelisted.\n"
|
|
53
|
+
}
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
expect(Array.from(container.querySelectorAll("p")).map((node) => node.textContent)).toEqual([
|
|
57
|
+
"You are not permitted to access this resource. Login to access",
|
|
58
|
+
"Function frappe.desk.form.load.getdoctype is not whitelisted.",
|
|
59
|
+
]);
|
|
60
|
+
});
|
|
44
61
|
});
|
|
45
62
|
|
|
46
63
|
/**
|