@astryxdesign/cli 0.4.7 → 0.5.0-canary.009bcb3
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/CHANGELOG.md +64 -0
- package/README.md +53 -51
- package/api/docs/docs.doc.mjs +2 -2
- package/api/index.d.mts +1 -1
- package/api/index.mjs +1 -1
- package/api/search/search.mjs +50 -4
- package/api/search/search.test.mjs +71 -0
- package/api/template/data-token-fallbacks.test.mjs +85 -0
- package/api/template/template.doc.mjs +2 -2
- package/api/theme/build/build.mjs +43 -44
- package/api/theme/targets/targets.d.mts +18 -0
- package/api/theme/targets/targets.mjs +87 -0
- package/api/theme/targets/targets.test.mjs +66 -0
- package/api/theme/theme.d.mts +1 -0
- package/api/theme/theme.mjs +3 -1
- package/api/theme/theme.type.d.mts +23 -0
- package/api/theme/theme.type.mjs +21 -1
- package/api/theme/themeTargets.doc.d.mts +11 -0
- package/api/theme/themeTargets.doc.mjs +58 -0
- package/api/theme/themeTemplate.doc.mjs +3 -3
- package/assets/codemods/__tests__/registry.test.mjs +1 -0
- package/assets/codemods/registry.mjs +1 -0
- package/assets/codemods/transforms/v0.5.0/__tests__/next-codemods.test.mjs +127 -0
- package/assets/codemods/transforms/v0.5.0/banner-collapsible-content.mjs +171 -0
- package/assets/codemods/transforms/v0.5.0/index.mjs +20 -0
- package/assets/docs/README.md +50 -0
- package/assets/docs/cli-integrations.doc.mjs +4 -4
- package/assets/docs/theme.doc.dense.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/docs/typography.doc.mjs +2 -2
- package/assets/templates/blocks/components/Banner/BannerCollapsibleContent.doc.mjs +1 -1
- package/assets/templates/blocks/components/Banner/BannerCollapsibleContent.tsx +1 -1
- package/assets/templates/blocks/components/DateInput/DateInputClearable.tsx +5 -1
- package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +6 -1
- package/assets/templates/blocks/components/DateInput/DateInputFormats.tsx +5 -1
- package/assets/templates/blocks/components/DateInput/DateInputShowcase.tsx +4 -1
- package/assets/templates/blocks/components/DateInput/DateInputWithDescription.tsx +5 -1
- package/assets/templates/blocks/components/DateInput/DateInputWithValidation.tsx +5 -1
- package/assets/templates/blocks/components/Dialog/DialogAdaptivePresentation.doc.mjs +25 -0
- package/assets/templates/blocks/components/Dialog/DialogAdaptivePresentation.tsx +167 -0
- package/assets/templates/blocks/components/Dialog/DialogScrollingContent.tsx +1 -1
- package/assets/templates/blocks/components/HoverCard/HoverCardHookUsage.tsx +4 -1
- package/assets/templates/blocks/components/Step/StepContent.doc.mjs +14 -0
- package/assets/templates/blocks/components/Step/StepContent.tsx +32 -0
- package/assets/templates/blocks/components/Step/StepIndicator.doc.mjs +14 -0
- package/assets/templates/blocks/components/Step/StepIndicator.tsx +60 -0
- package/assets/templates/blocks/components/Step/StepShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/Step/StepShowcase.tsx +26 -0
- package/assets/templates/blocks/components/Step/StepStates.doc.mjs +14 -0
- package/assets/templates/blocks/components/Step/StepStates.tsx +46 -0
- package/assets/templates/blocks/components/Stepper/StepperCustomContent.doc.mjs +22 -0
- package/assets/templates/blocks/components/Stepper/StepperCustomContent.tsx +126 -0
- package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.doc.mjs +1 -1
- package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.tsx +17 -5
- package/assets/templates/blocks/components/Stepper/StepperOnTrackHorizontal.doc.mjs +14 -0
- package/assets/templates/blocks/components/Stepper/StepperOnTrackHorizontal.tsx +25 -0
- package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.doc.mjs +2 -2
- package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.tsx +1 -1
- package/assets/templates/blocks/components/Stepper/StepperShowcase.doc.mjs +1 -1
- package/assets/templates/blocks/components/Stepper/StepperShowcase.tsx +6 -7
- package/assets/templates/blocks/components/Stepper/StepperStatus.tsx +1 -1
- package/assets/templates/pages/dashboard-cohort-funnel/page.tsx +1 -1
- package/assets/templates/pages/dashboard-data/page.tsx +1 -1
- package/assets/templates/pages/dashboard-portfolio/page.tsx +5 -5
- package/assets/templates/pages/dashboard-service-monitoring/page.tsx +1 -1
- package/assets/templates/pages/mixed-gallery/page.tsx +12 -3
- package/assets/templates/pages/settings-dialog/page.tsx +2543 -757
- package/assets/templates/pages/settings-dialog/template.doc.mjs +1 -2
- package/assets/templates/pages/table-filter/page.tsx +4093 -0
- package/assets/templates/pages/table-filter/template.doc.mjs +12 -0
- package/assets/templates/pages/table-grouped/page.tsx +151 -144
- package/assets/templates/pages/theme-showcase/page.tsx +36 -17
- package/assets/templates/themes/chocolate/chocolateTheme.ts +3 -1
- package/assets/templates/themes/matcha/matchaTheme.ts +3 -1
- package/assets/templates/themes/neutral/neutralTheme.ts +16 -9
- package/assets/templates/themes/stone/stoneTheme.ts +3 -1
- package/clients/cli/commands/build-theme.color-scheme.test.mjs +7 -6
- package/clients/cli/commands/build-theme.data-tokens.test.mjs +144 -0
- package/clients/cli/commands/build-theme.mjs +85 -0
- package/clients/cli/commands/build-theme.variants.test.mjs +3 -0
- package/clients/cli/commands/dialog-adaptive-template.test.mjs +24 -0
- package/clients/cli/commands/theme-targets.behavior.test.mjs +64 -0
- package/clients/cli/commands/theme-targets.doc.mjs +38 -0
- package/clients/cli/commands/theme-template.doc.mjs +2 -2
- package/clients/cli/commands/theme.doc.mjs +4 -2
- package/clients/cli/index.mjs +1 -0
- package/clients/cli/lib/component-format.mjs +2 -2
- package/clients/cli/lib/manifest.mjs +2 -0
- package/foundation/discovery/component-discovery.mjs +10 -9
- package/foundation/discovery/hook-discovery.mjs +2 -1
- package/foundation/discovery/hook-discovery.test.mjs +156 -37
- package/foundation/discovery/theming-targets.d.mts +86 -0
- package/foundation/discovery/theming-targets.mjs +202 -0
- package/foundation/discovery/theming-targets.test.mjs +245 -0
- package/foundation/fs/paths.d.mts +16 -0
- package/foundation/fs/paths.mjs +36 -0
- package/foundation/fs/paths.test.mjs +29 -1
- package/foundation/response/response-types.doc.mjs +7 -2
- package/package.json +9 -9
- package/assets/templates/blocks/components/Stepper/StepperHorizontal.doc.mjs +0 -14
- package/assets/templates/blocks/components/Stepper/StepperHorizontal.tsx +0 -24
- package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.doc.mjs +0 -14
- package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.tsx +0 -92
- package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.doc.mjs +0 -14
- package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.tsx +0 -40
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'page',
|
|
6
|
+
name: 'Filterable Table',
|
|
7
|
+
displayName: 'Filterable Table',
|
|
8
|
+
description:
|
|
9
|
+
'Filterable data table with a token filter bar that swaps to PowerSearch, saved views, view options for columns and grouping, and a resizable detail panel.',
|
|
10
|
+
isReady: true,
|
|
11
|
+
category: 'Table - Filtering',
|
|
12
|
+
};
|
|
@@ -37,6 +37,7 @@ import {Divider} from '@astryxdesign/core/Divider';
|
|
|
37
37
|
import {MetadataList, MetadataListItem} from '@astryxdesign/core/MetadataList';
|
|
38
38
|
import {
|
|
39
39
|
Table,
|
|
40
|
+
TableBody,
|
|
40
41
|
TableRow,
|
|
41
42
|
TableCell,
|
|
42
43
|
proportional,
|
|
@@ -963,161 +964,167 @@ export default function DataTableTemplate() {
|
|
|
963
964
|
/>
|
|
964
965
|
))}
|
|
965
966
|
</colgroup>
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
967
|
+
<TableBody>
|
|
968
|
+
{groupKeys.map(key => {
|
|
969
|
+
const tasks = grouped.get(key);
|
|
970
|
+
if (!tasks || tasks.length === 0) {
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
const isExpanded = expandedGroups.has(key);
|
|
972
974
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
<TableRow
|
|
977
|
-
role="button"
|
|
978
|
-
tabIndex={0}
|
|
979
|
-
onClick={() => toggleGroup(key)}
|
|
980
|
-
onKeyDown={e => {
|
|
981
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
982
|
-
e.preventDefault();
|
|
983
|
-
toggleGroup(key);
|
|
984
|
-
}
|
|
985
|
-
}}>
|
|
986
|
-
<TableCell colSpan={COL_COUNT} style={groupHeaderCell}>
|
|
987
|
-
<HStack gap={2} vAlign="center">
|
|
988
|
-
<Icon
|
|
989
|
-
icon={
|
|
990
|
-
isExpanded ? ChevronDownIcon : ChevronRightIcon
|
|
991
|
-
}
|
|
992
|
-
size="sm"
|
|
993
|
-
color="secondary"
|
|
994
|
-
/>
|
|
995
|
-
<Text type="body" weight="bold">
|
|
996
|
-
{getGroupLabel(groupBy, key)}
|
|
997
|
-
</Text>
|
|
998
|
-
<Badge
|
|
999
|
-
variant="neutral"
|
|
1000
|
-
label={String(tasks.length)}
|
|
1001
|
-
/>
|
|
1002
|
-
</HStack>
|
|
1003
|
-
</TableCell>
|
|
1004
|
-
</TableRow>
|
|
1005
|
-
)}
|
|
1006
|
-
{(groupBy === 'none' || isExpanded) &&
|
|
1007
|
-
tasks.map(task => (
|
|
975
|
+
return (
|
|
976
|
+
<React.Fragment key={key}>
|
|
977
|
+
{groupBy !== 'none' && (
|
|
1008
978
|
<TableRow
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
979
|
+
role="button"
|
|
980
|
+
tabIndex={0}
|
|
981
|
+
onClick={() => toggleGroup(key)}
|
|
982
|
+
onKeyDown={e => {
|
|
983
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
984
|
+
e.preventDefault();
|
|
985
|
+
toggleGroup(key);
|
|
986
|
+
}
|
|
987
|
+
}}>
|
|
988
|
+
<TableCell
|
|
989
|
+
colSpan={COL_COUNT}
|
|
990
|
+
style={groupHeaderCell}>
|
|
991
|
+
<HStack gap={2} vAlign="center">
|
|
1021
992
|
<Icon
|
|
1022
|
-
icon={
|
|
993
|
+
icon={
|
|
994
|
+
isExpanded
|
|
995
|
+
? ChevronDownIcon
|
|
996
|
+
: ChevronRightIcon
|
|
997
|
+
}
|
|
1023
998
|
size="sm"
|
|
1024
|
-
color=
|
|
999
|
+
color="secondary"
|
|
1025
1000
|
/>
|
|
1026
|
-
<Text type="
|
|
1027
|
-
{
|
|
1001
|
+
<Text type="body" weight="bold">
|
|
1002
|
+
{getGroupLabel(groupBy, key)}
|
|
1028
1003
|
</Text>
|
|
1029
|
-
<
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
<Text
|
|
1034
|
-
type="body"
|
|
1035
|
-
color="secondary"
|
|
1036
|
-
maxLines={1}>
|
|
1037
|
-
› {task.subtitle}
|
|
1038
|
-
</Text>
|
|
1039
|
-
)}
|
|
1004
|
+
<Badge
|
|
1005
|
+
variant="neutral"
|
|
1006
|
+
label={String(tasks.length)}
|
|
1007
|
+
/>
|
|
1040
1008
|
</HStack>
|
|
1041
1009
|
</TableCell>
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1010
|
+
</TableRow>
|
|
1011
|
+
)}
|
|
1012
|
+
{(groupBy === 'none' || isExpanded) &&
|
|
1013
|
+
tasks.map(task => (
|
|
1014
|
+
<TableRow
|
|
1015
|
+
key={task.id}
|
|
1016
|
+
onClick={() => setSelectedTask(task)}>
|
|
1017
|
+
<TableCell>
|
|
1018
|
+
<Center axis="horizontal">
|
|
1019
|
+
<StatusDot
|
|
1020
|
+
variant={STATUS_DOT_VARIANT[task.status]}
|
|
1021
|
+
label={STATUS_LABEL[task.status]}
|
|
1022
|
+
/>
|
|
1023
|
+
</Center>
|
|
1024
|
+
</TableCell>
|
|
1025
|
+
<TableCell>
|
|
1026
|
+
<HStack gap={3} vAlign="center">
|
|
1027
|
+
<Icon
|
|
1028
|
+
icon={ChartBarIcon}
|
|
1029
|
+
size="sm"
|
|
1030
|
+
color={PRIORITY_COLOR[task.priority]}
|
|
1031
|
+
/>
|
|
1032
|
+
<Text type="supporting" color="secondary">
|
|
1033
|
+
{task.taskId}
|
|
1034
|
+
</Text>
|
|
1035
|
+
<Text type="body" maxLines={1}>
|
|
1036
|
+
{task.title}
|
|
1037
|
+
</Text>
|
|
1038
|
+
{task.subtitle && (
|
|
1039
|
+
<Text
|
|
1040
|
+
type="body"
|
|
1041
|
+
color="secondary"
|
|
1042
|
+
maxLines={1}>
|
|
1043
|
+
› {task.subtitle}
|
|
1044
|
+
</Text>
|
|
1045
|
+
)}
|
|
1046
|
+
</HStack>
|
|
1047
|
+
</TableCell>
|
|
1048
|
+
<TableCell>
|
|
1049
|
+
{task.project ? (
|
|
1050
|
+
<Text type="body" maxLines={1}>
|
|
1051
|
+
{task.project}
|
|
1052
|
+
</Text>
|
|
1053
|
+
) : (
|
|
1054
|
+
<Text type="supporting" color="secondary">
|
|
1055
|
+
—
|
|
1056
|
+
</Text>
|
|
1057
|
+
)}
|
|
1058
|
+
</TableCell>
|
|
1059
|
+
<TableCell>
|
|
1060
|
+
<Text type="supporting" color="secondary">
|
|
1061
|
+
{task.created}
|
|
1046
1062
|
</Text>
|
|
1047
|
-
|
|
1063
|
+
</TableCell>
|
|
1064
|
+
<TableCell>
|
|
1048
1065
|
<Text type="supporting" color="secondary">
|
|
1049
|
-
|
|
1066
|
+
{task.updated}
|
|
1050
1067
|
</Text>
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
onClick: () => {},
|
|
1112
|
-
},
|
|
1113
|
-
]}
|
|
1114
|
-
/>
|
|
1115
|
-
</TableCell>
|
|
1116
|
-
</TableRow>
|
|
1117
|
-
))}
|
|
1118
|
-
</React.Fragment>
|
|
1119
|
-
);
|
|
1120
|
-
})}
|
|
1068
|
+
</TableCell>
|
|
1069
|
+
<TableCell>
|
|
1070
|
+
<Avatar name={task.assignee} size="sm" />
|
|
1071
|
+
</TableCell>
|
|
1072
|
+
<TableCell>
|
|
1073
|
+
<DropdownMenu
|
|
1074
|
+
button={{
|
|
1075
|
+
label: 'Actions',
|
|
1076
|
+
variant: 'ghost',
|
|
1077
|
+
size: 'sm',
|
|
1078
|
+
icon: (
|
|
1079
|
+
<Icon
|
|
1080
|
+
icon={EllipsisHorizontalIcon}
|
|
1081
|
+
size="sm"
|
|
1082
|
+
/>
|
|
1083
|
+
),
|
|
1084
|
+
isIconOnly: true,
|
|
1085
|
+
}}
|
|
1086
|
+
hasChevron={false}
|
|
1087
|
+
items={[
|
|
1088
|
+
{
|
|
1089
|
+
label: 'Edit issue',
|
|
1090
|
+
icon: PencilIcon,
|
|
1091
|
+
onClick: () => {},
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
label: 'Assign to...',
|
|
1095
|
+
icon: UserIcon,
|
|
1096
|
+
onClick: () => {},
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
label: 'Add label',
|
|
1100
|
+
icon: TagIcon,
|
|
1101
|
+
onClick: () => {},
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
label: 'Duplicate',
|
|
1105
|
+
icon: DocumentDuplicateIcon,
|
|
1106
|
+
onClick: () => {},
|
|
1107
|
+
},
|
|
1108
|
+
{
|
|
1109
|
+
label: 'Move to project',
|
|
1110
|
+
icon: ArrowRightIcon,
|
|
1111
|
+
onClick: () => {},
|
|
1112
|
+
},
|
|
1113
|
+
{type: 'divider' as const},
|
|
1114
|
+
{
|
|
1115
|
+
label: 'Delete issue',
|
|
1116
|
+
icon: TrashIcon,
|
|
1117
|
+
onClick: () => {},
|
|
1118
|
+
},
|
|
1119
|
+
]}
|
|
1120
|
+
/>
|
|
1121
|
+
</TableCell>
|
|
1122
|
+
</TableRow>
|
|
1123
|
+
))}
|
|
1124
|
+
</React.Fragment>
|
|
1125
|
+
);
|
|
1126
|
+
})}
|
|
1127
|
+
</TableBody>
|
|
1121
1128
|
</Table>
|
|
1122
1129
|
</LayoutContent>
|
|
1123
1130
|
}
|
|
@@ -153,14 +153,16 @@ const styles: Record<string, CSSProperties> = {
|
|
|
153
153
|
flex: 1,
|
|
154
154
|
},
|
|
155
155
|
quantityInput: {
|
|
156
|
-
// minWidth (not a hard width) so the field grows to fit the digit + the
|
|
157
|
-
// theme's input padding. A fixed 40px was too tight on themes with larger
|
|
158
|
-
// padding / bigger type scale (e.g. Matcha, Y2K), clipping the value.
|
|
159
|
-
minWidth: 64,
|
|
160
156
|
flexShrink: 0,
|
|
161
157
|
},
|
|
158
|
+
// `auto` basis so the button wraps to its own line rather than ellipsizing.
|
|
162
159
|
cartButton: {
|
|
163
|
-
flex: 1,
|
|
160
|
+
flex: '1 1 auto',
|
|
161
|
+
minWidth: 0,
|
|
162
|
+
},
|
|
163
|
+
cartRow: {
|
|
164
|
+
width: '100%',
|
|
165
|
+
minWidth: 0,
|
|
164
166
|
},
|
|
165
167
|
};
|
|
166
168
|
|
|
@@ -236,6 +238,18 @@ const inlineStyles: Record<string, CSSProperties> = {
|
|
|
236
238
|
display: 'flex',
|
|
237
239
|
flexDirection: 'column',
|
|
238
240
|
},
|
|
241
|
+
// Flex bases, not grid tracks: the checkout form needs a width floor, and the
|
|
242
|
+
// chat wraps to its own row rather than squeezing it under one.
|
|
243
|
+
checkoutColumn: {
|
|
244
|
+
flex: '1 1 300px',
|
|
245
|
+
minWidth: 0,
|
|
246
|
+
display: 'grid',
|
|
247
|
+
},
|
|
248
|
+
chatColumn: {
|
|
249
|
+
flex: '2 1 520px',
|
|
250
|
+
minWidth: 0,
|
|
251
|
+
display: 'grid',
|
|
252
|
+
},
|
|
239
253
|
};
|
|
240
254
|
|
|
241
255
|
const PRODUCT_IMAGE_KEYS = ['watch', 'headphones', 'backpack'];
|
|
@@ -284,8 +298,7 @@ const DEFAULT_PRODUCTS: ProductSpec[] = [
|
|
|
284
298
|
// scaffolded template renders real imagery without needing local public assets.
|
|
285
299
|
const DEFAULT_IMAGES: Record<string, string> = {
|
|
286
300
|
watch: '/template-assets/Neutral-Watch.png',
|
|
287
|
-
headphones:
|
|
288
|
-
'/template-assets/Neutral-Headphones.png',
|
|
301
|
+
headphones: '/template-assets/Neutral-Headphones.png',
|
|
289
302
|
backpack: '/template-assets/Neutral-Backpack.png',
|
|
290
303
|
wallet: '/template-assets/Neutral-Wallet.png',
|
|
291
304
|
tumbler: '/template-assets/Neutral-Tumbler.png',
|
|
@@ -350,14 +363,14 @@ function CardShowcase({
|
|
|
350
363
|
|
|
351
364
|
return (
|
|
352
365
|
<VStack gap={8}>
|
|
353
|
-
<
|
|
354
|
-
<
|
|
366
|
+
<HStack gap={4} wrap="wrap">
|
|
367
|
+
<div style={inlineStyles.checkoutColumn}>
|
|
355
368
|
<CheckoutCard isMobile={isMobile} />
|
|
356
|
-
</
|
|
357
|
-
<
|
|
369
|
+
</div>
|
|
370
|
+
<div style={inlineStyles.chatColumn}>
|
|
358
371
|
<ChatCard />
|
|
359
|
-
</
|
|
360
|
-
</
|
|
372
|
+
</div>
|
|
373
|
+
</HStack>
|
|
361
374
|
<Grid columns={columns} gap={4}>
|
|
362
375
|
<GridSpan columns={isMobile ? 1 : 3}>
|
|
363
376
|
<InventoryCard images={images} inventory={inventory} />
|
|
@@ -472,7 +485,12 @@ function StorePreview({
|
|
|
472
485
|
}}>
|
|
473
486
|
{p.description}
|
|
474
487
|
</Text>
|
|
475
|
-
<HStack
|
|
488
|
+
<HStack
|
|
489
|
+
gap={2}
|
|
490
|
+
vAlign="center"
|
|
491
|
+
hAlign="center"
|
|
492
|
+
wrap="wrap"
|
|
493
|
+
style={styles.cartRow}>
|
|
476
494
|
<NumberInput
|
|
477
495
|
label="Quantity"
|
|
478
496
|
isLabelHidden
|
|
@@ -481,6 +499,7 @@ function StorePreview({
|
|
|
481
499
|
min={1}
|
|
482
500
|
max={99}
|
|
483
501
|
size="sm"
|
|
502
|
+
width={72}
|
|
484
503
|
style={styles.quantityInput}
|
|
485
504
|
/>
|
|
486
505
|
<Button
|
|
@@ -506,7 +525,7 @@ function StorePreview({
|
|
|
506
525
|
|
|
507
526
|
function CheckoutCard({isMobile}: {isMobile: boolean}) {
|
|
508
527
|
return (
|
|
509
|
-
<Card padding={5} style={styles.card}>
|
|
528
|
+
<Card padding={isMobile ? 4 : 5} style={styles.card}>
|
|
510
529
|
<VStack gap={4} style={styles.checkoutStack}>
|
|
511
530
|
<Heading level={2}>Checkout</Heading>
|
|
512
531
|
|
|
@@ -560,7 +579,7 @@ function CheckoutCard({isMobile}: {isMobile: boolean}) {
|
|
|
560
579
|
<Text type="supporting" weight="bold">
|
|
561
580
|
Payment method
|
|
562
581
|
</Text>
|
|
563
|
-
<Grid columns={isMobile ? 1 : {minWidth:
|
|
582
|
+
<Grid columns={isMobile ? 1 : {minWidth: 80, max: 3}} gap={2}>
|
|
564
583
|
<SelectableCard
|
|
565
584
|
label="Pay with card"
|
|
566
585
|
isSelected={true}
|
|
@@ -614,7 +633,7 @@ function CheckoutCard({isMobile}: {isMobile: boolean}) {
|
|
|
614
633
|
placeholder="1234 1234 1234 1234"
|
|
615
634
|
value=""
|
|
616
635
|
onChange={() => {}}
|
|
617
|
-
startIcon={<CreditCard size={16} />}
|
|
636
|
+
startIcon={isMobile ? undefined : <CreditCard size={16} />}
|
|
618
637
|
size="lg"
|
|
619
638
|
/>
|
|
620
639
|
|
|
@@ -27,7 +27,9 @@ const chocolateSyntax = defineSyntaxTheme({
|
|
|
27
27
|
tag: ['#8c3a3a', '#d47a7a'],
|
|
28
28
|
attribute: ['#8C5927', '#d4a06a'],
|
|
29
29
|
property: ['#3a7c6b', '#70c4b0'],
|
|
30
|
-
|
|
30
|
+
// #B88859/#6b5540 failed WCAG AA against the syntax background: 3.06:1
|
|
31
|
+
// light, 2.56:1 dark. #5386.
|
|
32
|
+
punctuation: ['#9e622e', '#cb884d'], // 4.84:1 / 6.12:1
|
|
31
33
|
background: ['#FFFCF7', '#1c1610'],
|
|
32
34
|
},
|
|
33
35
|
});
|
|
@@ -27,7 +27,9 @@ const matchaSyntax = defineSyntaxTheme({
|
|
|
27
27
|
tag: ['#8c3a3a', '#d47a7a'],
|
|
28
28
|
attribute: ['#7c5e3a', '#c4a882'],
|
|
29
29
|
property: ['#3a7c6b', '#70c4b0'],
|
|
30
|
-
|
|
30
|
+
// #707E46/#5a6440 failed WCAG AA against the syntax background: 3.83:1
|
|
31
|
+
// light, 2.73:1 dark. #5386.
|
|
32
|
+
punctuation: ['#566a39', '#92af6a'], // 5.19:1 / 7.02:1
|
|
31
33
|
background: ['#F0F0E0', '#1a1c14'],
|
|
32
34
|
},
|
|
33
35
|
});
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
* icon = T30 / T80
|
|
25
25
|
* text = T30 / T80
|
|
26
26
|
*
|
|
27
|
-
* All 9 saturated badge values pass WCAG AA (5
|
|
27
|
+
* All 9 saturated badge values pass WCAG AA against their label (>= 4.5:1);
|
|
28
|
+
* `scripts/check-badge-contrast.test.mjs` holds every theme to that.
|
|
28
29
|
*
|
|
29
30
|
* Only overrides tokens that differ from the defaults.
|
|
30
31
|
*/
|
|
@@ -51,7 +52,9 @@ const neutralSyntax = defineSyntaxTheme({
|
|
|
51
52
|
tag: ['#89001a', '#ffaeaa'], // red
|
|
52
53
|
attribute: ['#584400', '#eec12f'], // yellow
|
|
53
54
|
property: ['#005348', '#83dac9'], // teal
|
|
54
|
-
|
|
55
|
+
// #a3a3a3/#525252 (this pair's own disabled-text tone) failed WCAG AA
|
|
56
|
+
// against the syntax background: 2.42:1 light, 2.53:1 dark. #5386.
|
|
57
|
+
punctuation: ['#6e6e6e', '#a0a0a0'], // neutral, 4.89:1 / 7.57:1
|
|
55
58
|
background: ['#fafafa', '#0a0a0a'],
|
|
56
59
|
},
|
|
57
60
|
});
|
|
@@ -432,10 +435,14 @@ export const neutralTheme = defineTheme({
|
|
|
432
435
|
color: '#171717',
|
|
433
436
|
},
|
|
434
437
|
'variant:error': {
|
|
435
|
-
// Light: T55 #e33f4a
|
|
438
|
+
// Light: T58 #c9303a. The T55 stop #e33f4a pairs with white at only
|
|
439
|
+
// 4.14:1 — the label is 12px/500, so AA wants 4.5, not the 3:1
|
|
440
|
+
// large-text allowance. One tonal step down holds the hue
|
|
441
|
+
// (OKLCH H 21.9 -> 22.8, C 0.200 -> 0.189) and reaches 5.29:1.
|
|
436
442
|
// Dark : T60 stop from dark-mode tonal palette of Tailwind red-600
|
|
437
|
-
// source #dc2626 (kept on H=27 alarm-red rather than coral)
|
|
438
|
-
|
|
443
|
+
// source #dc2626 (kept on H=27 alarm-red rather than coral).
|
|
444
|
+
// Dark text on it is 6.60:1 and unchanged.
|
|
445
|
+
backgroundColor: 'light-dark(#c9303a, #ff705d)',
|
|
439
446
|
color: 'light-dark(#ffffff, #171717)',
|
|
440
447
|
},
|
|
441
448
|
|
|
@@ -500,7 +507,7 @@ export const neutralTheme = defineTheme({
|
|
|
500
507
|
//
|
|
501
508
|
// success → badge success bg (green T45 / dark-ramp T60)
|
|
502
509
|
// warning → badge warning bg (yellow T85, same hex both modes)
|
|
503
|
-
// error → badge error bg (red
|
|
510
|
+
// error → badge error bg (red T58 / dark-ramp T60)
|
|
504
511
|
// accent → badge info bg (blue T50 / dark-ramp T60) — the
|
|
505
512
|
// StatusDot "accent" is the info/attention color, so it
|
|
506
513
|
// pairs with the info badge rather than --color-accent
|
|
@@ -515,7 +522,7 @@ export const neutralTheme = defineTheme({
|
|
|
515
522
|
statusdot: {
|
|
516
523
|
'variant:success': {backgroundColor: 'light-dark(#198100, #64af4c)'},
|
|
517
524
|
'variant:warning': {backgroundColor: '#ffce2f'},
|
|
518
|
-
'variant:error': {backgroundColor: 'light-dark(#
|
|
525
|
+
'variant:error': {backgroundColor: 'light-dark(#c9303a, #ff705d)'},
|
|
519
526
|
'variant:accent': {backgroundColor: 'light-dark(#0074e2, #6d9cfe)'},
|
|
520
527
|
},
|
|
521
528
|
|
|
@@ -611,8 +618,8 @@ export const neutralTheme = defineTheme({
|
|
|
611
618
|
'--color-warning': '#ffce2f',
|
|
612
619
|
},
|
|
613
620
|
'variant:error': {
|
|
614
|
-
// Red
|
|
615
|
-
'--color-error': '#
|
|
621
|
+
// Red T58 saturated stop (= variant:error badge bg)
|
|
622
|
+
'--color-error': '#c9303a',
|
|
616
623
|
},
|
|
617
624
|
},
|
|
618
625
|
|
|
@@ -105,7 +105,9 @@ export const stoneTheme = defineTheme({
|
|
|
105
105
|
|
|
106
106
|
// Text — H=291
|
|
107
107
|
'--color-text-primary': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
|
|
108
|
-
|
|
108
|
+
// T40/T70 keeps normal secondary text above AA on every stone surface,
|
|
109
|
+
// including the muted and tinted fills that components pair it with.
|
|
110
|
+
'--color-text-secondary': ['#5e5e63', '#ababb0'], // Stone Neutral T40 / T70
|
|
109
111
|
'--color-text-disabled': ['#d7d7da', '#5e5e61'], // T86 C=1.6 / T40 C=2
|
|
110
112
|
'--color-text-accent': ['#25252a', '#f3f3f5'], // light: Stone Neutral T15
|
|
111
113
|
'--color-on-dark': '#FFFFFF',
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
* html[data-theme="dark"] { color-scheme: dark; }
|
|
18
18
|
*
|
|
19
19
|
* Themes that never use `light-dark()` have no `color-scheme` ambiguity to
|
|
20
|
-
* resolve, so none of the three rules should be emitted for them
|
|
20
|
+
* resolve, so none of the three rules should be emitted for them — the
|
|
21
|
+
* generated CSS still carries the `--color-data-*` defaults, which are
|
|
22
|
+
* `light-dark()` pairs, so the decision reads the theme's own values.
|
|
21
23
|
*
|
|
22
24
|
* Building `astryx theme build` requires a compiled @astryxdesign/core (there is no in-CLI
|
|
23
25
|
* fallback generator), so this suite builds core once in beforeAll via the
|
|
@@ -67,10 +69,9 @@ describe('theme build color-scheme output', () => {
|
|
|
67
69
|
const project = path.join(tmpDir, 'project');
|
|
68
70
|
const themesDir = path.join(project, 'themes');
|
|
69
71
|
// A raw light-dark() token value is what triggers the color-scheme
|
|
70
|
-
// injection in build-theme.mjs
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
// the string directly so this test stays focused on the CLI's own
|
|
72
|
+
// injection in build-theme.mjs. `defineTheme.test.ts` already covers the
|
|
73
|
+
// separate [light, dark] tuple -> light-dark() conversion; this fixture
|
|
74
|
+
// writes the string directly so this test stays focused on the CLI's own
|
|
74
75
|
// color-scheme decision, not on that conversion.
|
|
75
76
|
const themeFile = writeTheme(themesDir, 'with-light-dark', {
|
|
76
77
|
'--color-accent': 'light-dark(#0077B6, #48CAE4)',
|
|
@@ -123,7 +124,7 @@ describe('theme build color-scheme output', () => {
|
|
|
123
124
|
expect(fs.existsSync(cssPath)).toBe(true);
|
|
124
125
|
const css = fs.readFileSync(cssPath, 'utf-8');
|
|
125
126
|
|
|
126
|
-
expect(css).
|
|
127
|
+
expect(css).toContain('--color-accent: #0077B6');
|
|
127
128
|
expect(css).not.toContain(COLOR_SCHEME_ROOT_DECL);
|
|
128
129
|
expect(css).not.toContain(COLOR_SCHEME_LIGHT_DECL);
|
|
129
130
|
expect(css).not.toContain(COLOR_SCHEME_DARK_DECL);
|