@discourser/design-system 0.25.0 → 0.25.2
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/figma-codex/resolver.d.ts.map +1 -1
- package/dist/figma-codex.json +301 -15
- package/package.json +1 -1
- package/src/components/RadioGroup.figma.tsx +26 -3
- package/src/components/Slider.figma.tsx +48 -2
- package/src/components/Switch.figma.tsx +17 -0
- package/src/figma-codex/resolver.ts +116 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/figma-codex/resolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/figma-codex/resolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,UAAU,CAAC;AA8SlB,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,gBAAgB,GACvB,cAAc,CAyEhB"}
|
package/dist/figma-codex.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
3
|
"packageName": "@discourser/design-system",
|
|
4
|
-
"generatedAt": "2026-03-
|
|
5
|
-
"gitHash": "
|
|
4
|
+
"generatedAt": "2026-03-31T15:43:15.946Z",
|
|
5
|
+
"gitHash": "c57712c8",
|
|
6
6
|
"figmaFiles": {
|
|
7
7
|
"GaHmFfmvO4loUzuZS4TgEz": {
|
|
8
8
|
"fileKey": "GaHmFfmvO4loUzuZS4TgEz"
|
|
@@ -20,7 +20,13 @@
|
|
|
20
20
|
"imports": {
|
|
21
21
|
"primary": "import * as Accordion from '@discourser/design-system/Accordion'",
|
|
22
22
|
"namedExports": [
|
|
23
|
-
"Accordion.ItemBody"
|
|
23
|
+
"Accordion.ItemBody",
|
|
24
|
+
"Accordion.Root",
|
|
25
|
+
"Accordion.RootProvider",
|
|
26
|
+
"Accordion.Item",
|
|
27
|
+
"Accordion.ItemContent",
|
|
28
|
+
"Accordion.ItemIndicator",
|
|
29
|
+
"Accordion.ItemTrigger"
|
|
24
30
|
],
|
|
25
31
|
"subpath": "@discourser/design-system/Accordion"
|
|
26
32
|
},
|
|
@@ -29,6 +35,30 @@
|
|
|
29
35
|
{
|
|
30
36
|
"name": "ItemBody",
|
|
31
37
|
"element": "div"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "Root",
|
|
41
|
+
"element": "root"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "RootProvider",
|
|
45
|
+
"element": "root"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "Item",
|
|
49
|
+
"element": "item"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "ItemContent",
|
|
53
|
+
"element": "itemContent"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "ItemIndicator",
|
|
57
|
+
"element": "itemIndicator"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "ItemTrigger",
|
|
61
|
+
"element": "itemTrigger"
|
|
32
62
|
}
|
|
33
63
|
],
|
|
34
64
|
"example": "<Accordion.Root collapsible>\n <Accordion.Item value=\"item-1\">\n <Accordion.ItemTrigger>\n <span>Trigger</span>\n <Accordion.ItemIndicator />\n </Accordion.ItemTrigger>\n <Accordion.ItemContent>Content</Accordion.ItemContent>\n </Accordion.Item>\n </Accordion.Root>",
|
|
@@ -716,12 +746,92 @@
|
|
|
716
746
|
},
|
|
717
747
|
"imports": {
|
|
718
748
|
"primary": "import * as RadioGroup from '@discourser/design-system/RadioGroup'",
|
|
719
|
-
"namedExports": [
|
|
749
|
+
"namedExports": [
|
|
750
|
+
"RadioGroup.Root",
|
|
751
|
+
"RadioGroup.RootProvider",
|
|
752
|
+
"RadioGroup.Indicator",
|
|
753
|
+
"RadioGroup.Item",
|
|
754
|
+
"RadioGroup.ItemControl",
|
|
755
|
+
"RadioGroup.ItemText",
|
|
756
|
+
"RadioGroup.Label"
|
|
757
|
+
],
|
|
720
758
|
"subpath": "@discourser/design-system/RadioGroup"
|
|
721
759
|
},
|
|
722
|
-
"props": [
|
|
723
|
-
|
|
724
|
-
|
|
760
|
+
"props": [
|
|
761
|
+
{
|
|
762
|
+
"name": "value",
|
|
763
|
+
"type": "string",
|
|
764
|
+
"required": false,
|
|
765
|
+
"description": "controlled selected value (string)"
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
"name": "defaultValue",
|
|
769
|
+
"type": "string",
|
|
770
|
+
"required": false,
|
|
771
|
+
"description": "uncontrolled initial value (string)"
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
"name": "onValueChange",
|
|
775
|
+
"type": "({ value }: { value: string }) => void",
|
|
776
|
+
"required": false,
|
|
777
|
+
"description": "callback ({ value }: { value: string }) => void"
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
"name": "disabled",
|
|
781
|
+
"type": "boolean",
|
|
782
|
+
"required": false,
|
|
783
|
+
"description": "boolean, disables all items"
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
"name": "orientation",
|
|
787
|
+
"type": "'horizontal' | 'vertical'",
|
|
788
|
+
"required": false,
|
|
789
|
+
"description": "'horizontal' | 'vertical' (default: 'vertical')"
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
"name": "value",
|
|
793
|
+
"type": "string",
|
|
794
|
+
"required": false,
|
|
795
|
+
"description": "required unique string for this option"
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
"name": "disabled",
|
|
799
|
+
"type": "boolean",
|
|
800
|
+
"required": false,
|
|
801
|
+
"description": "boolean, disables this item only"
|
|
802
|
+
}
|
|
803
|
+
],
|
|
804
|
+
"subComponents": [
|
|
805
|
+
{
|
|
806
|
+
"name": "Root",
|
|
807
|
+
"element": "root"
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
"name": "RootProvider",
|
|
811
|
+
"element": "root"
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
"name": "Indicator",
|
|
815
|
+
"element": "indicator"
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
"name": "Item",
|
|
819
|
+
"element": "item"
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
"name": "ItemControl",
|
|
823
|
+
"element": "itemControl"
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
"name": "ItemText",
|
|
827
|
+
"element": "itemText"
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
"name": "Label",
|
|
831
|
+
"element": "label"
|
|
832
|
+
}
|
|
833
|
+
],
|
|
834
|
+
"example": "<RadioGroup.Root defaultValue=\"option-1\">\n <RadioGroup.Item value=\"option-1\">\n <RadioGroup.ItemControl />\n <RadioGroup.ItemText>Option 1</RadioGroup.ItemText>\n </RadioGroup.Item>\n <RadioGroup.Item value=\"option-2\">\n <RadioGroup.ItemControl />\n <RadioGroup.ItemText>Option 2</RadioGroup.ItemText>\n </RadioGroup.Item>\n <RadioGroup.Item value=\"option-3\">\n <RadioGroup.ItemControl />\n <RadioGroup.ItemText>Option 3</RadioGroup.ItemText>\n </RadioGroup.Item>\n </RadioGroup.Root>",
|
|
725
835
|
"sourcePath": "src/components/RadioGroup.tsx",
|
|
726
836
|
"tokens": {
|
|
727
837
|
"recipe": "radioGroup",
|
|
@@ -931,13 +1041,142 @@
|
|
|
931
1041
|
},
|
|
932
1042
|
"imports": {
|
|
933
1043
|
"primary": "import * as Slider from '@discourser/design-system/Slider'",
|
|
934
|
-
"namedExports": [
|
|
1044
|
+
"namedExports": [
|
|
1045
|
+
"Slider.Control",
|
|
1046
|
+
"Slider.Track",
|
|
1047
|
+
"Slider.Range",
|
|
1048
|
+
"Slider.Root",
|
|
1049
|
+
"Slider.Thumb",
|
|
1050
|
+
"Slider.Label",
|
|
1051
|
+
"Slider.ValueText",
|
|
1052
|
+
"Slider.Marker",
|
|
1053
|
+
"Slider.MarkerGroup",
|
|
1054
|
+
"Slider.MarkerIndicator",
|
|
1055
|
+
"Slider.DraggingIndicator",
|
|
1056
|
+
"Slider.Marks"
|
|
1057
|
+
],
|
|
935
1058
|
"subpath": "@discourser/design-system/Slider"
|
|
936
1059
|
},
|
|
937
|
-
"props": [
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1060
|
+
"props": [
|
|
1061
|
+
{
|
|
1062
|
+
"name": "defaultValue",
|
|
1063
|
+
"type": "string",
|
|
1064
|
+
"required": false,
|
|
1065
|
+
"description": "uncontrolled initial value array, e.g. [50]"
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
"name": "value",
|
|
1069
|
+
"type": "string",
|
|
1070
|
+
"required": false,
|
|
1071
|
+
"description": "controlled value array, e.g. [50]"
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
"name": "onValueChange",
|
|
1075
|
+
"type": "({ value }: { value: number[] }) => void",
|
|
1076
|
+
"required": false,
|
|
1077
|
+
"description": "callback ({ value }: { value: number[] }) => void"
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
"name": "min",
|
|
1081
|
+
"type": "string",
|
|
1082
|
+
"required": false,
|
|
1083
|
+
"description": "number (default: 0)"
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
"name": "max",
|
|
1087
|
+
"type": "string",
|
|
1088
|
+
"required": false,
|
|
1089
|
+
"description": "number (default: 100)"
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
"name": "step",
|
|
1093
|
+
"type": "string",
|
|
1094
|
+
"required": false,
|
|
1095
|
+
"description": "number (default: 1)"
|
|
1096
|
+
},
|
|
1097
|
+
{
|
|
1098
|
+
"name": "orientation",
|
|
1099
|
+
"type": "'horizontal' | 'vertical'",
|
|
1100
|
+
"required": false,
|
|
1101
|
+
"description": "'horizontal' | 'vertical' (default: 'horizontal')"
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
"name": "disabled",
|
|
1105
|
+
"type": "boolean",
|
|
1106
|
+
"required": false,
|
|
1107
|
+
"description": "boolean"
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
"name": "colorPalette",
|
|
1111
|
+
"type": "'primary' | 'secondary' | 'tertiary' | 'neutral' | 'error'",
|
|
1112
|
+
"required": false,
|
|
1113
|
+
"description": "'primary' | 'secondary' | 'tertiary' | 'neutral' | 'error'"
|
|
1114
|
+
}
|
|
1115
|
+
],
|
|
1116
|
+
"subComponents": [
|
|
1117
|
+
{
|
|
1118
|
+
"name": "Control",
|
|
1119
|
+
"element": "control"
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
"name": "Track",
|
|
1123
|
+
"element": "track"
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
"name": "Range",
|
|
1127
|
+
"element": "range"
|
|
1128
|
+
},
|
|
1129
|
+
{
|
|
1130
|
+
"name": "Root",
|
|
1131
|
+
"element": "div"
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"name": "Thumb",
|
|
1135
|
+
"element": "div"
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
"name": "Label",
|
|
1139
|
+
"element": "label"
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
"name": "ValueText",
|
|
1143
|
+
"element": "div"
|
|
1144
|
+
},
|
|
1145
|
+
{
|
|
1146
|
+
"name": "Marker",
|
|
1147
|
+
"element": "span"
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
"name": "MarkerGroup",
|
|
1151
|
+
"element": "div"
|
|
1152
|
+
},
|
|
1153
|
+
{
|
|
1154
|
+
"name": "MarkerIndicator",
|
|
1155
|
+
"element": "div"
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
"name": "DraggingIndicator",
|
|
1159
|
+
"element": "div"
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
"name": "Marks",
|
|
1163
|
+
"element": "div"
|
|
1164
|
+
}
|
|
1165
|
+
],
|
|
1166
|
+
"example": "<Slider.Root defaultValue={[50]} orientation={orientation}>\n <Slider.Label>Volume</Slider.Label>\n <Slider.Control>\n <Slider.Track>\n <Slider.Range />\n </Slider.Track>\n <Slider.Thumbs />\n </Slider.Control>\n </Slider.Root>",
|
|
1167
|
+
"sourcePath": "src/components/Slider.tsx",
|
|
1168
|
+
"tokens": {
|
|
1169
|
+
"recipe": "slider",
|
|
1170
|
+
"variantProps": [
|
|
1171
|
+
"orientation",
|
|
1172
|
+
"size",
|
|
1173
|
+
"variant"
|
|
1174
|
+
],
|
|
1175
|
+
"figmaPropToRecipeProp": {
|
|
1176
|
+
"Orientation": "orientation",
|
|
1177
|
+
"Size": "size"
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
941
1180
|
},
|
|
942
1181
|
"Stepper": {
|
|
943
1182
|
"name": "Stepper",
|
|
@@ -1063,11 +1302,58 @@
|
|
|
1063
1302
|
},
|
|
1064
1303
|
"imports": {
|
|
1065
1304
|
"primary": "import * as Switch from '@discourser/design-system/Switch'",
|
|
1066
|
-
"namedExports": [
|
|
1305
|
+
"namedExports": [
|
|
1306
|
+
"Switch.Root",
|
|
1307
|
+
"Switch.Label",
|
|
1308
|
+
"Switch.Thumb",
|
|
1309
|
+
"Switch.Control"
|
|
1310
|
+
],
|
|
1067
1311
|
"subpath": "@discourser/design-system/Switch"
|
|
1068
1312
|
},
|
|
1069
|
-
"props": [
|
|
1070
|
-
|
|
1313
|
+
"props": [
|
|
1314
|
+
{
|
|
1315
|
+
"name": "defaultChecked",
|
|
1316
|
+
"type": "boolean",
|
|
1317
|
+
"required": false,
|
|
1318
|
+
"description": "uncontrolled initial state (boolean)"
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
"name": "checked",
|
|
1322
|
+
"type": "boolean",
|
|
1323
|
+
"required": false,
|
|
1324
|
+
"description": "controlled state (boolean)"
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
"name": "onCheckedChange",
|
|
1328
|
+
"type": "({ checked }: { checked: boolean }) => void",
|
|
1329
|
+
"required": false,
|
|
1330
|
+
"description": "callback ({ checked }: { checked: boolean }) => void"
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
"name": "disabled",
|
|
1334
|
+
"type": "boolean",
|
|
1335
|
+
"required": false,
|
|
1336
|
+
"description": "boolean"
|
|
1337
|
+
}
|
|
1338
|
+
],
|
|
1339
|
+
"subComponents": [
|
|
1340
|
+
{
|
|
1341
|
+
"name": "Root",
|
|
1342
|
+
"element": "root"
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
"name": "Label",
|
|
1346
|
+
"element": "label"
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
"name": "Thumb",
|
|
1350
|
+
"element": "thumb"
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
"name": "Control",
|
|
1354
|
+
"element": "control"
|
|
1355
|
+
}
|
|
1356
|
+
],
|
|
1071
1357
|
"example": "<Switch.Root defaultChecked={checked}>\n <Switch.Control />\n <Switch.Label>Toggle</Switch.Label>\n </Switch.Root>",
|
|
1072
1358
|
"sourcePath": "src/components/Switch.tsx",
|
|
1073
1359
|
"tokens": {
|
package/package.json
CHANGED
|
@@ -12,6 +12,25 @@ import * as RadioGroup from './RadioGroup';
|
|
|
12
12
|
// Original designer-built component — .Radio Group Radio Toggle (38:8893)
|
|
13
13
|
// Variants: Checked(False/True) × State(Default/Focus/Disabled)
|
|
14
14
|
// This is the component used in production Discourser.AI page designs.
|
|
15
|
+
//
|
|
16
|
+
// Anatomy:
|
|
17
|
+
// <RadioGroup.Root value={string} onValueChange={fn}>
|
|
18
|
+
// <RadioGroup.Item value="x">
|
|
19
|
+
// <RadioGroup.ItemControl />
|
|
20
|
+
// <RadioGroup.ItemText>Label</RadioGroup.ItemText>
|
|
21
|
+
// </RadioGroup.Item>
|
|
22
|
+
// </RadioGroup.Root>
|
|
23
|
+
//
|
|
24
|
+
// Key props on Root:
|
|
25
|
+
// value — controlled selected value (string)
|
|
26
|
+
// defaultValue — uncontrolled initial value (string)
|
|
27
|
+
// onValueChange — callback ({ value }: { value: string }) => void
|
|
28
|
+
// disabled — boolean, disables all items
|
|
29
|
+
// orientation — 'horizontal' | 'vertical' (default: 'vertical')
|
|
30
|
+
//
|
|
31
|
+
// Key props on Item:
|
|
32
|
+
// value — required unique string for this option
|
|
33
|
+
// disabled — boolean, disables this item only
|
|
15
34
|
figma.connect(
|
|
16
35
|
RadioGroup.Root,
|
|
17
36
|
'https://www.figma.com/design/GaHmFfmvO4loUzuZS4TgEz/Discourser.AI--V1?node-id=38-8893',
|
|
@@ -23,15 +42,19 @@ figma.connect(
|
|
|
23
42
|
}),
|
|
24
43
|
},
|
|
25
44
|
example: ({ checked: _checked }) => (
|
|
26
|
-
<RadioGroup.Root>
|
|
27
|
-
<RadioGroup.Item value="
|
|
45
|
+
<RadioGroup.Root defaultValue="option-1">
|
|
46
|
+
<RadioGroup.Item value="option-1">
|
|
28
47
|
<RadioGroup.ItemControl />
|
|
29
48
|
<RadioGroup.ItemText>Option 1</RadioGroup.ItemText>
|
|
30
49
|
</RadioGroup.Item>
|
|
31
|
-
<RadioGroup.Item value="
|
|
50
|
+
<RadioGroup.Item value="option-2">
|
|
32
51
|
<RadioGroup.ItemControl />
|
|
33
52
|
<RadioGroup.ItemText>Option 2</RadioGroup.ItemText>
|
|
34
53
|
</RadioGroup.Item>
|
|
54
|
+
<RadioGroup.Item value="option-3">
|
|
55
|
+
<RadioGroup.ItemControl />
|
|
56
|
+
<RadioGroup.ItemText>Option 3</RadioGroup.ItemText>
|
|
57
|
+
</RadioGroup.Item>
|
|
35
58
|
</RadioGroup.Root>
|
|
36
59
|
),
|
|
37
60
|
},
|
|
@@ -1,12 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @dds-tokens
|
|
3
|
+
* recipe: slider
|
|
4
|
+
* variantProps: orientation, size, variant
|
|
5
|
+
* figmaPropToRecipeProp:
|
|
6
|
+
* Orientation: orientation
|
|
7
|
+
* Size: size
|
|
8
|
+
*/
|
|
1
9
|
import figma from '@figma/code-connect';
|
|
2
10
|
import * as Slider from './Slider';
|
|
3
11
|
|
|
12
|
+
// Original designer-built component — Discourser AI Slider (38:7988)
|
|
13
|
+
// This is the component used in production Discourser.AI page designs.
|
|
14
|
+
//
|
|
15
|
+
// Import as namespace: import * as Slider from '@discourser/design-system/Slider'
|
|
16
|
+
//
|
|
17
|
+
// Anatomy:
|
|
18
|
+
// <Slider.Root defaultValue={[number]} min={number} max={number} step={number}>
|
|
19
|
+
// <Slider.Label>Label text</Slider.Label>
|
|
20
|
+
// <Slider.Control>
|
|
21
|
+
// <Slider.Track>
|
|
22
|
+
// <Slider.Range />
|
|
23
|
+
// </Slider.Track>
|
|
24
|
+
// <Slider.Thumbs /> ← convenience component, renders one Thumb per value
|
|
25
|
+
// </Slider.Control>
|
|
26
|
+
// <Slider.ValueText /> ← optional, displays current value
|
|
27
|
+
// </Slider.Root>
|
|
28
|
+
//
|
|
29
|
+
// Key props on Root:
|
|
30
|
+
// defaultValue — uncontrolled initial value array, e.g. [50]
|
|
31
|
+
// value — controlled value array, e.g. [50]
|
|
32
|
+
// onValueChange — callback ({ value }: { value: number[] }) => void
|
|
33
|
+
// min — number (default: 0)
|
|
34
|
+
// max — number (default: 100)
|
|
35
|
+
// step — number (default: 1)
|
|
36
|
+
// orientation — 'horizontal' | 'vertical' (default: 'horizontal')
|
|
37
|
+
// disabled — boolean
|
|
38
|
+
// colorPalette — 'primary' | 'secondary' | 'tertiary' | 'neutral' | 'error'
|
|
39
|
+
//
|
|
40
|
+
// Convenience components:
|
|
41
|
+
// <Slider.Thumbs /> — renders one Thumb per value entry (use instead of
|
|
42
|
+
// manually mapping Slider.Thumb with index props)
|
|
43
|
+
// <Slider.Marks marks={[0, 25, 50, 75, 100]} /> — renders a MarkerGroup
|
|
4
44
|
figma.connect(
|
|
5
45
|
Slider.Root,
|
|
6
46
|
'https://www.figma.com/design/GaHmFfmvO4loUzuZS4TgEz/Discourser.AI--V1?node-id=38-7988',
|
|
7
47
|
{
|
|
8
|
-
|
|
9
|
-
|
|
48
|
+
props: {
|
|
49
|
+
orientation: figma.enum('Orientation', {
|
|
50
|
+
Horizontal: 'horizontal',
|
|
51
|
+
Vertical: 'vertical',
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
example: ({ orientation }) => (
|
|
55
|
+
<Slider.Root defaultValue={[50]} orientation={orientation}>
|
|
10
56
|
<Slider.Label>Volume</Slider.Label>
|
|
11
57
|
<Slider.Control>
|
|
12
58
|
<Slider.Track>
|
|
@@ -12,6 +12,23 @@ import * as Switch from './Switch';
|
|
|
12
12
|
// Original designer-built component — Discourser AI Switch Toggle (38:8121)
|
|
13
13
|
// Variants: Toggled(False/True) × State(Default/Focus/Disabled)
|
|
14
14
|
// This is the component used in production Discourser.AI page designs.
|
|
15
|
+
//
|
|
16
|
+
// Import as namespace: import * as Switch from '@discourser/design-system/Switch'
|
|
17
|
+
//
|
|
18
|
+
// Anatomy:
|
|
19
|
+
// <Switch.Root defaultChecked={bool}>
|
|
20
|
+
// <Switch.Control /> ← renders the track + thumb internally
|
|
21
|
+
// <Switch.Label>Label text</Switch.Label>
|
|
22
|
+
// </Switch.Root>
|
|
23
|
+
//
|
|
24
|
+
// Key props on Root:
|
|
25
|
+
// defaultChecked — uncontrolled initial state (boolean)
|
|
26
|
+
// checked — controlled state (boolean)
|
|
27
|
+
// onCheckedChange — callback ({ checked }: { checked: boolean }) => void
|
|
28
|
+
// disabled — boolean
|
|
29
|
+
//
|
|
30
|
+
// Note: Switch.Control includes Switch.Thumb by default via defaultProps.
|
|
31
|
+
// Do NOT add <Switch.Thumb> manually inside <Switch.Control>.
|
|
15
32
|
figma.connect(
|
|
16
33
|
Switch.Root,
|
|
17
34
|
'https://www.figma.com/design/GaHmFfmvO4loUzuZS4TgEz/Discourser.AI--V1?node-id=38-8121',
|
|
@@ -38,13 +38,93 @@ function resolveImplementationFile(sourceFile: string): string {
|
|
|
38
38
|
return sourceFile;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
41
|
+
function inferTypeFromDescription(description: string): string {
|
|
42
|
+
const desc = description.trim();
|
|
43
|
+
|
|
44
|
+
// Direct type keyword at start
|
|
45
|
+
const directType = desc.match(
|
|
46
|
+
/^(boolean|string|number|string\[\]|number\[\])(\s*[,.]|$)/,
|
|
47
|
+
);
|
|
48
|
+
if (directType) return directType[1];
|
|
49
|
+
|
|
50
|
+
// Parenthesized type at end: "description (boolean)"
|
|
51
|
+
const parenEnd = desc.match(/\(([a-zA-Z[\]]+)\)\s*$/);
|
|
52
|
+
if (parenEnd && /^(boolean|string|number)(\[\])?$/.test(parenEnd[1])) {
|
|
53
|
+
return parenEnd[1];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Union of string literals: 'a' | 'b' | 'c' — possibly with trailing " (default: ...)"
|
|
57
|
+
if (/^'[^']+'(\s*\|\s*'[^']+')+/.test(desc)) {
|
|
58
|
+
const match = desc.match(/^('(?:[^']+)'\s*(?:\|\s*'(?:[^']+)'\s*)*)/);
|
|
59
|
+
if (match) return match[1].trim();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Callback: "callback (...) => void"
|
|
63
|
+
if (desc.startsWith('callback')) {
|
|
64
|
+
const rest = desc.replace(/^callback\s+/, '');
|
|
65
|
+
return rest || '(...args: unknown[]) => void';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return 'string';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function extractPropsFromFigmaJsdoc(figmaFilePath: string): PropDefinition[] {
|
|
72
|
+
if (!existsSync(figmaFilePath)) return [];
|
|
73
|
+
const content = readFileSync(figmaFilePath, 'utf-8');
|
|
74
|
+
const props: PropDefinition[] = [];
|
|
75
|
+
|
|
76
|
+
const lines = content.split('\n');
|
|
77
|
+
let inPropsSection = false;
|
|
78
|
+
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
const trimmed = line.trim();
|
|
81
|
+
|
|
82
|
+
if (!trimmed.startsWith('//')) {
|
|
83
|
+
if (inPropsSection) break; // left the comment block
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Strip the leading `//` (and optional single space)
|
|
88
|
+
const commentContent = trimmed.replace(/^\/\/\s?/, '');
|
|
89
|
+
|
|
90
|
+
if (/^Key props/i.test(commentContent)) {
|
|
91
|
+
inPropsSection = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!inPropsSection) continue;
|
|
96
|
+
|
|
97
|
+
// Match " propName — description" (em-dash, en-dash, or hyphen)
|
|
98
|
+
const propMatch = commentContent.match(/^\s+(\w+)\s+[—–-]+\s+(.+)$/);
|
|
99
|
+
if (propMatch) {
|
|
100
|
+
const [, name, description] = propMatch;
|
|
101
|
+
const type = inferTypeFromDescription(description);
|
|
102
|
+
props.push({
|
|
103
|
+
name,
|
|
104
|
+
type,
|
|
105
|
+
required: false,
|
|
106
|
+
description: description.trim(),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return props;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function extractProps(
|
|
115
|
+
sourceContent: string,
|
|
116
|
+
figmaFilePath?: string,
|
|
117
|
+
): PropDefinition[] {
|
|
42
118
|
const props: PropDefinition[] = [];
|
|
43
119
|
|
|
44
120
|
// Step 1: Find the Props interface and extract its full body using balanced-brace tracking
|
|
45
121
|
const ifaceRe = /interface\s+\w+Props\s*\{/g;
|
|
46
122
|
const startMatch = ifaceRe.exec(sourceContent);
|
|
47
|
-
if (!startMatch)
|
|
123
|
+
if (!startMatch) {
|
|
124
|
+
// Fallback: no interface found — read Key props section from the .figma.tsx JSDoc
|
|
125
|
+
if (figmaFilePath) return extractPropsFromFigmaJsdoc(figmaFilePath);
|
|
126
|
+
return props;
|
|
127
|
+
}
|
|
48
128
|
|
|
49
129
|
// Find the opening { of the interface body
|
|
50
130
|
const openBrace = sourceContent.indexOf(
|
|
@@ -157,15 +237,41 @@ function extractProps(sourceContent: string): PropDefinition[] {
|
|
|
157
237
|
}
|
|
158
238
|
|
|
159
239
|
function extractSubComponents(sourceContent: string): SubComponentEntry[] {
|
|
160
|
-
const subs
|
|
161
|
-
const re =
|
|
162
|
-
/export\s+const\s+(\w+)\s+=\s+with(?:Provider|Context)\(ark\.(\w+)/g;
|
|
240
|
+
const subs = new Map<string, SubComponentEntry>();
|
|
163
241
|
let m: RegExpExecArray | null;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
242
|
+
|
|
243
|
+
// Pattern 1: withProvider/withContext(ark.tagName, ...) — Park UI ark factory
|
|
244
|
+
const arkRe =
|
|
245
|
+
/export\s+const\s+(\w+)\s+=\s+with(?:Provider|Context)\(ark\.(\w+)/g;
|
|
246
|
+
while ((m = arkRe.exec(sourceContent)) !== null) {
|
|
247
|
+
subs.set(m[1], { name: m[1], element: m[2] });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Pattern 2: withProvider/withContext(Namespace.Sub, 'slotName') — styleContext pattern
|
|
251
|
+
// Used by RadioGroup, Switch, and similar Ark UI compound components
|
|
252
|
+
const styleCtxRe =
|
|
253
|
+
/export\s+const\s+(\w+)\s+=\s+with(?:Provider|Context)\(\s*\w+\.\w+\s*,\s*['"](\w+)['"]/g;
|
|
254
|
+
while ((m = styleCtxRe.exec(sourceContent)) !== null) {
|
|
255
|
+
if (!subs.has(m[1])) subs.set(m[1], { name: m[1], element: m[2] });
|
|
167
256
|
}
|
|
168
|
-
|
|
257
|
+
|
|
258
|
+
// Pattern 3: createStyledComponent(Namespace.Sub, 'slotName', ...) — custom styled wrapper
|
|
259
|
+
// Used by Slider and similar components with manual style context
|
|
260
|
+
const styledRe =
|
|
261
|
+
/export\s+const\s+(\w+)\s+=\s+createStyledComponent\(\s*\w+\.\w+\s*,\s*['"](\w+)['"]/g;
|
|
262
|
+
while ((m = styledRe.exec(sourceContent)) !== null) {
|
|
263
|
+
if (!subs.has(m[1])) subs.set(m[1], { name: m[1], element: m[2] });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Pattern 4: forwardRef<HTMLXxxElement, ...> — typed forward ref exports
|
|
267
|
+
const forwardRefRe =
|
|
268
|
+
/export\s+const\s+(\w+)\s+=\s+forwardRef<HTML(\w+)Element/g;
|
|
269
|
+
while ((m = forwardRefRe.exec(sourceContent)) !== null) {
|
|
270
|
+
if (!subs.has(m[1]))
|
|
271
|
+
subs.set(m[1], { name: m[1], element: m[2].toLowerCase() });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return Array.from(subs.values());
|
|
169
275
|
}
|
|
170
276
|
|
|
171
277
|
function classifyComponent(
|
|
@@ -237,7 +343,7 @@ export function resolveComponent(
|
|
|
237
343
|
}
|
|
238
344
|
|
|
239
345
|
const componentType = classifyComponent(parsed, sourceContent);
|
|
240
|
-
const props = extractProps(typesContent);
|
|
346
|
+
const props = extractProps(typesContent, parsed.filePath);
|
|
241
347
|
const subComponents =
|
|
242
348
|
componentType === 'compound'
|
|
243
349
|
? extractSubComponents(sourceContent)
|