@tscircuit/props 0.0.626 → 0.0.627

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.
@@ -45,6 +45,27 @@ export interface PinHeaderProps extends CommonComponentProps {
45
45
  */
46
46
  gender?: "male" | "female" | "unpopulated"
47
47
 
48
+ /**
49
+ * Mount the header on the top of the board, so it is connected to from
50
+ * above. An alias for `layer: "top"`, which is the default.
51
+ *
52
+ * Which side of the board a part sits on is `layer`, and only `layer`: the
53
+ * 3D model is always drawn top-side and consumers flip it for a bottom-layer
54
+ * component. Prefer these names on a connector, where "which side does the
55
+ * mating connector come from" is the question actually being asked.
56
+ */
57
+ connectsFromAbove?: boolean
58
+
59
+ /**
60
+ * Mount the header on the underside of the board, so it is connected to from
61
+ * below. An alias for `layer: "bottom"`.
62
+ *
63
+ * Not to be confused with `invert` on a footprint string, which installs a
64
+ * header BACKWARDS on whichever side it is on — long pins through the board
65
+ * rather than short ones.
66
+ */
67
+ connectsFromBelow?: boolean
68
+
48
69
  /**
49
70
  * Whether to show pin labels in silkscreen
50
71
  */
@@ -122,33 +143,61 @@ export interface PinHeaderProps extends CommonComponentProps {
122
143
  schHeight?: number | string
123
144
  }
124
145
 
125
- export const pinHeaderProps = commonComponentProps.extend({
126
- pinCount: z.number(),
127
- pitch: distance.optional(),
128
- schFacingDirection: z.enum(["up", "down", "left", "right"]).optional(),
129
- gender: z.enum(["male", "female", "unpopulated"]).optional().default("male"),
130
- showSilkscreenPinLabels: z.boolean().optional(),
131
- pcbPinLabels: z.record(z.string(), z.string()).optional(),
132
- doubleRow: z.boolean().optional(),
133
- rightAngle: z.boolean().optional(),
134
- pcbOrientation: pcbOrientationProp.optional(),
135
- holeDiameter: distance.optional(),
136
- platedDiameter: distance.optional(),
137
- pinLabels: z
138
- .record(z.string(), schematicPinLabel)
139
- .or(z.array(schematicPinLabel))
140
- .optional(),
141
- connections: z
142
- .custom<Connections>()
143
- .pipe(z.record(z.string(), connectionTarget))
144
- .optional(),
145
- facingDirection: z.enum(["left", "right"]).optional(),
146
- schPinArrangement: schematicPinArrangement.optional(),
147
- schPinStyle: schematicPinStyle.optional(),
148
- schPinSpacing: distance.optional(),
149
- schWidth: distance.optional(),
150
- schHeight: distance.optional(),
151
- })
146
+ export const pinHeaderProps = commonComponentProps
147
+ .extend({
148
+ pinCount: z.number(),
149
+ pitch: distance.optional(),
150
+ schFacingDirection: z.enum(["up", "down", "left", "right"]).optional(),
151
+ gender: z
152
+ .enum(["male", "female", "unpopulated"])
153
+ .optional()
154
+ .default("male"),
155
+ showSilkscreenPinLabels: z.boolean().optional(),
156
+ pcbPinLabels: z.record(z.string(), z.string()).optional(),
157
+ doubleRow: z.boolean().optional(),
158
+ rightAngle: z.boolean().optional(),
159
+ pcbOrientation: pcbOrientationProp.optional(),
160
+ holeDiameter: distance.optional(),
161
+ platedDiameter: distance.optional(),
162
+ pinLabels: z
163
+ .record(z.string(), schematicPinLabel)
164
+ .or(z.array(schematicPinLabel))
165
+ .optional(),
166
+ connections: z
167
+ .custom<Connections>()
168
+ .pipe(z.record(z.string(), connectionTarget))
169
+ .optional(),
170
+ facingDirection: z.enum(["left", "right"]).optional(),
171
+ schPinArrangement: schematicPinArrangement.optional(),
172
+ schPinStyle: schematicPinStyle.optional(),
173
+ schPinSpacing: distance.optional(),
174
+ schWidth: distance.optional(),
175
+ schHeight: distance.optional(),
176
+ connectsFromAbove: z.boolean().optional(),
177
+ connectsFromBelow: z.boolean().optional(),
178
+ })
179
+ // Resolved HERE rather than in each consumer: `layer` is read in dozens of
180
+ // places downstream, and an alias that only some of them understand is worse
181
+ // than no alias. After parsing there is one field to reason about again.
182
+ .superRefine((props, ctx) => {
183
+ if (props.connectsFromAbove && props.connectsFromBelow) {
184
+ ctx.addIssue({
185
+ code: z.ZodIssueCode.custom,
186
+ message:
187
+ "connectsFromAbove and connectsFromBelow are opposites; set at most one",
188
+ })
189
+ }
190
+ })
191
+ .transform((props) => {
192
+ const layer =
193
+ props.layer ??
194
+ (props.connectsFromBelow
195
+ ? ("bottom" as const)
196
+ : props.connectsFromAbove
197
+ ? ("top" as const)
198
+ : undefined)
199
+ return layer === undefined ? props : { ...props, layer }
200
+ })
152
201
 
153
202
  type InferredPinHeaderProps = z.input<typeof pinHeaderProps>
154
203
  expectTypesMatch<PinHeaderProps, InferredPinHeaderProps>(true)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/props",
3
- "version": "0.0.626",
3
+ "version": "0.0.627",
4
4
  "description": "Props for tscircuit builtin component types",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",