@tscircuit/props 0.0.618 → 0.0.619
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/README.md +20 -0
- package/dist/index.d.ts +24097 -119
- package/dist/index.js +21 -4
- package/dist/index.js.map +1 -1
- package/lib/common/cadModel.ts +22 -0
- package/lib/components/footprint.ts +25 -0
- package/lib/enclosure/cutout-aperture.ts +75 -13
- package/lib/enclosure/fdm/box.ts +40 -0
- package/package.json +1 -1
package/lib/common/cadModel.ts
CHANGED
|
@@ -38,6 +38,27 @@ export interface CadModelBase {
|
|
|
38
38
|
y: number | string
|
|
39
39
|
z: number | string
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Axis-aligned extent of the model measured in its own coordinate frame, the
|
|
43
|
+
* same frame as `modelOriginPosition`.
|
|
44
|
+
*
|
|
45
|
+
* `size` gives the extent but not where the box sits relative to the model
|
|
46
|
+
* origin, and the box is generally not centered on it, so `size` alone cannot
|
|
47
|
+
* say how much of the part is above the board. Since `modelOriginPosition` is
|
|
48
|
+
* the point placed on the board surface, these bounds supply the missing
|
|
49
|
+
* term. `modelBoardNormalDirection` names the axis (default `z+`): for a
|
|
50
|
+
* positive normal the outward reach is `max[axis] - origin[axis]`, and for a
|
|
51
|
+
* negative one it is `origin[axis] - min[axis]`.
|
|
52
|
+
*
|
|
53
|
+
* These are the model's own bounds, before `modelUnitToMmScale` or any
|
|
54
|
+
* object-fit scaling is applied.
|
|
55
|
+
*
|
|
56
|
+
* Whatever generates a part file already measures this to produce `size`.
|
|
57
|
+
*/
|
|
58
|
+
modelBounds?: {
|
|
59
|
+
min: { x: number | string; y: number | string; z: number | string }
|
|
60
|
+
max: { x: number | string; y: number | string; z: number | string }
|
|
61
|
+
}
|
|
41
62
|
size?: { x: number | string; y: number | string; z: number | string }
|
|
42
63
|
modelUnitToMmScale?: Distance
|
|
43
64
|
modelBoardNormalDirection?: CadModelAxisDirection
|
|
@@ -51,6 +72,7 @@ export const cadModelBase = z.object({
|
|
|
51
72
|
rotationOffset: z.number().or(rotationPoint3).optional(),
|
|
52
73
|
positionOffset: point3.optional(),
|
|
53
74
|
modelOriginPosition: point3.optional(),
|
|
75
|
+
modelBounds: z.object({ min: point3, max: point3 }).optional(),
|
|
54
76
|
size: point3.optional(),
|
|
55
77
|
modelUnitToMmScale: distance.optional(),
|
|
56
78
|
modelBoardNormalDirection: cadModelAxisDirection.optional(),
|
|
@@ -81,6 +81,26 @@ export interface FootprintProps {
|
|
|
81
81
|
* makes the distinction easy to miss.
|
|
82
82
|
*/
|
|
83
83
|
insertionDirection?: FootprintInsertionDirection
|
|
84
|
+
/**
|
|
85
|
+
* Direction the part's enclosure opening faces, named the same way as
|
|
86
|
+
* `insertionDirection` and in the same unrotated part frame.
|
|
87
|
+
*
|
|
88
|
+
* These are two different physical facts and a part may need both. A
|
|
89
|
+
* side-actuated switch is *installed* from above and *actuated* from the side:
|
|
90
|
+
* its aperture must pierce a side wall, while nothing is ever inserted into
|
|
91
|
+
* it. Reusing `insertionDirection` for that would either put the opening on
|
|
92
|
+
* the wrong face or overload a field documented as "the side exposing the
|
|
93
|
+
* receptacle where the cable is attached".
|
|
94
|
+
*
|
|
95
|
+
* Like `insertionDirection`, this is a property of the part, authored without
|
|
96
|
+
* regard to placement: rotating or flipping the component rotates it too, and
|
|
97
|
+
* `pcb_component.cutout_aperture_direction` reports the result in board
|
|
98
|
+
* coordinates.
|
|
99
|
+
*
|
|
100
|
+
* When absent, the aperture falls back to `insertionDirection`, which is
|
|
101
|
+
* correct for every connector -- a cable enters through the opening it needs.
|
|
102
|
+
*/
|
|
103
|
+
cutoutApertureDirection?: FootprintInsertionDirection
|
|
84
104
|
}
|
|
85
105
|
|
|
86
106
|
export const footprintProps = z.object({
|
|
@@ -94,6 +114,11 @@ export const footprintProps = z.object({
|
|
|
94
114
|
.describe(
|
|
95
115
|
"Direction a cable or mating part is attached from, named for the side of the footprint it approaches from, in its unrotated orientation.",
|
|
96
116
|
),
|
|
117
|
+
cutoutApertureDirection: footprintInsertionDirection
|
|
118
|
+
.optional()
|
|
119
|
+
.describe(
|
|
120
|
+
"Direction the part's enclosure opening faces, in its unrotated orientation. Distinct from insertionDirection: a side-actuated switch is installed from above and actuated from the side. Falls back to insertionDirection when absent.",
|
|
121
|
+
),
|
|
97
122
|
})
|
|
98
123
|
|
|
99
124
|
export type FootprintPropsInput = z.input<typeof footprintProps>
|
|
@@ -19,30 +19,91 @@ export type EnclosureCutoutApertureShape = CommonShapeProps["shape"]
|
|
|
19
19
|
* Describes the nominal enclosure opening required by a component.
|
|
20
20
|
*
|
|
21
21
|
* Numeric values are interpreted as mm.
|
|
22
|
+
*
|
|
23
|
+
* ## Frame of reference
|
|
24
|
+
*
|
|
25
|
+
* An aperture is authored around the owning part's interaction axis, derived
|
|
26
|
+
* from its footprint `cutoutApertureDirection` or `insertionDirection`. On a
|
|
27
|
+
* side opening, `height` is board Z, `width` is perpendicular to that axis in
|
|
28
|
+
* the board plane, and `depth` follows the axis inboard. On the lid or floor,
|
|
29
|
+
* width and height rotate in-plane with the footprint and depth is vertical.
|
|
30
|
+
*
|
|
31
|
+
* The enclosure face is resolved later from where the transformed axis first
|
|
32
|
+
* intersects the box; it supplies a material plane, not the aperture's original
|
|
33
|
+
* coordinate frame.
|
|
22
34
|
*/
|
|
23
|
-
export interface
|
|
35
|
+
export interface CutoutApertureProps {
|
|
24
36
|
/** Additional clearance around the nominal opening. */
|
|
25
37
|
margin?: Distance
|
|
38
|
+
/**
|
|
39
|
+
* Move the opening's **center** across the face it pierces, along the same two
|
|
40
|
+
* axes its `width` and `height` are measured in. Both may be negative.
|
|
41
|
+
*
|
|
42
|
+
* Sharing a frame with the dimensions is the point. These replace
|
|
43
|
+
* `zExtentAboveBoard`, which only made sense on the four walls: on the lid and
|
|
44
|
+
* the floor an opening does not move in Z at all, so a "Z extent" had no
|
|
45
|
+
* meaning there.
|
|
46
|
+
*
|
|
47
|
+
* Zero means "wherever the part puts it", which is usually right. On a side
|
|
48
|
+
* face the opening is centred on the part's body above the board, taken from
|
|
49
|
+
* the model's measured bounds, so it lines up with the connector without
|
|
50
|
+
* anyone computing a height. On the lid or the floor it is centred on the
|
|
51
|
+
* part's own position, and both offsets turn with the part.
|
|
52
|
+
*
|
|
53
|
+
* `heightDimensionOffset` runs **outward** from the mounting surface on a side
|
|
54
|
+
* face -- up for a top-mounted part, down for a bottom-mounted one -- so, like
|
|
55
|
+
* the default it shifts, it describes the part rather than where the part was
|
|
56
|
+
* placed. A negative value pulls the opening back toward and past the board,
|
|
57
|
+
* which is what a cable jacket fatter than its connector needs; the binding
|
|
58
|
+
* constraint is that the opening must not cut into the floor.
|
|
59
|
+
*/
|
|
60
|
+
widthDimensionOffset?: Distance
|
|
61
|
+
/** See `widthDimensionOffset`. */
|
|
62
|
+
heightDimensionOffset?: Distance
|
|
63
|
+
/**
|
|
64
|
+
* How far the cutting tool continues inboard along the part's interaction
|
|
65
|
+
* axis, so the lid lip or other material behind the wall cannot obstruct it.
|
|
66
|
+
* On a side opening this axis may be oblique to X/Y; on the lid or floor it is
|
|
67
|
+
* vertical. The profile is cut as authored and never capped, so an explicitly
|
|
68
|
+
* excessive depth can reach the shell on the far side.
|
|
69
|
+
*
|
|
70
|
+
* Usually unnecessary: side depth is derived from the rotated CAD-body/PCB
|
|
71
|
+
* envelope. Horizontal depth uses the model's measured reach from the board
|
|
72
|
+
* and converts it to the cavity span beyond the plate's inner surface; where
|
|
73
|
+
* bounds are absent, `cadModel.size.z` is a less accurate fallback because it
|
|
74
|
+
* can include pins and through-board geometry.
|
|
75
|
+
*
|
|
76
|
+
* Set this where that envelope is wrong for the purpose -- for example a
|
|
77
|
+
* tapered body -- or where a part has no CAD model.
|
|
78
|
+
*/
|
|
79
|
+
depth?: Distance
|
|
26
80
|
}
|
|
27
81
|
|
|
28
|
-
export interface
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
82
|
+
export interface PillEnclosureCutoutApertureProps
|
|
83
|
+
extends PillShapeProps,
|
|
84
|
+
CutoutApertureProps {}
|
|
32
85
|
|
|
33
|
-
export interface
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
86
|
+
export interface RectEnclosureCutoutApertureProps
|
|
87
|
+
extends RectShapeProps,
|
|
88
|
+
CutoutApertureProps {}
|
|
89
|
+
|
|
90
|
+
export interface CircleEnclosureCutoutApertureProps
|
|
91
|
+
extends CircleShapeProps,
|
|
92
|
+
CutoutApertureProps {}
|
|
37
93
|
|
|
38
94
|
export type EnclosureCutoutApertureProps =
|
|
39
95
|
| PillEnclosureCutoutApertureProps
|
|
40
96
|
| RectEnclosureCutoutApertureProps
|
|
41
97
|
| CircleEnclosureCutoutApertureProps
|
|
42
98
|
|
|
43
|
-
const
|
|
99
|
+
export const cutoutApertureBaseProps = z.object({
|
|
44
100
|
margin: distance.optional(),
|
|
45
|
-
|
|
101
|
+
widthDimensionOffset: distance.optional(),
|
|
102
|
+
heightDimensionOffset: distance.optional(),
|
|
103
|
+
depth: distance.optional(),
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const apertureOnlyProps = cutoutApertureBaseProps.shape
|
|
46
107
|
|
|
47
108
|
export const enclosureCutoutApertureProps = z.discriminatedUnion("shape", [
|
|
48
109
|
pillShapeProps.extend(apertureOnlyProps),
|
|
@@ -50,10 +111,11 @@ export const enclosureCutoutApertureProps = z.discriminatedUnion("shape", [
|
|
|
50
111
|
circleShapeProps.extend(apertureOnlyProps),
|
|
51
112
|
])
|
|
52
113
|
|
|
53
|
-
type
|
|
114
|
+
export type ParsedEnclosureCutoutApertureProps = z.output<
|
|
54
115
|
typeof enclosureCutoutApertureProps
|
|
55
116
|
>
|
|
56
|
-
|
|
117
|
+
|
|
118
|
+
type InferredEnclosureCutoutApertureProps = z.input<
|
|
57
119
|
typeof enclosureCutoutApertureProps
|
|
58
120
|
>
|
|
59
121
|
|
package/lib/enclosure/fdm/box.ts
CHANGED
|
@@ -3,20 +3,60 @@ import { expectTypesMatch } from "lib/typecheck"
|
|
|
3
3
|
import { z } from "zod"
|
|
4
4
|
|
|
5
5
|
export interface EnclosureFdmBoxProps {
|
|
6
|
+
/** Stable enclosure identity. */
|
|
7
|
+
name?: string
|
|
6
8
|
/** The name or selector of the board enclosed by this box. */
|
|
7
9
|
boardRef: string
|
|
10
|
+
/** Optional outside X dimension; inferred from the board when omitted. */
|
|
8
11
|
width?: Distance
|
|
12
|
+
/** Optional outside Y dimension; inferred from the board when omitted. */
|
|
9
13
|
height?: Distance
|
|
14
|
+
/** Optional total outside Z dimension; inferred from the board stack. */
|
|
10
15
|
depth?: Distance
|
|
16
|
+
/** Printed side-wall thickness. */
|
|
11
17
|
wallThickness?: Distance
|
|
18
|
+
/** Base floor thickness. */
|
|
19
|
+
floorThickness?: Distance
|
|
20
|
+
/** Lid top-plate thickness. */
|
|
21
|
+
lidThickness?: Distance
|
|
22
|
+
/** Horizontal clearance between the board edge and inside wall. */
|
|
23
|
+
boardClearance?: Distance
|
|
24
|
+
/** Gap from the inside floor to the PCB bottom. */
|
|
25
|
+
standoffHeight?: Distance
|
|
26
|
+
/**
|
|
27
|
+
* Clearance from the PCB top surface up to the inside of the lid.
|
|
28
|
+
*
|
|
29
|
+
* This is measured from the *board*, not from the tallest component: only
|
|
30
|
+
* parts that declare an aperture report their height, so an arbitrary tall
|
|
31
|
+
* capacitor is invisible here and setting this does not guarantee it clears.
|
|
32
|
+
*
|
|
33
|
+
* Omit it and the depth is inferred instead -- grown until the lid and its lip
|
|
34
|
+
* clear every side-wall aperture, so a connector taller than the default
|
|
35
|
+
* cannot end up straddling the base/lid seam. Setting it explicitly opts out
|
|
36
|
+
* of that: the value is then taken literally, which is what allows a part to
|
|
37
|
+
* deliberately poke through the lid.
|
|
38
|
+
*/
|
|
39
|
+
topHeadroom?: Distance
|
|
40
|
+
/** Depth of the friction-fit lid lip. */
|
|
41
|
+
lidLipDepth?: Distance
|
|
42
|
+
/** Disable placement of apertures explicitly declared by enclosed components. */
|
|
43
|
+
disableCutouts?: boolean
|
|
12
44
|
}
|
|
13
45
|
|
|
14
46
|
export const enclosureFdmBoxProps = z.object({
|
|
47
|
+
name: z.string().optional(),
|
|
15
48
|
boardRef: z.string().min(1),
|
|
16
49
|
width: distance.optional(),
|
|
17
50
|
height: distance.optional(),
|
|
18
51
|
depth: distance.optional(),
|
|
19
52
|
wallThickness: distance.default("2mm"),
|
|
53
|
+
floorThickness: distance.optional(),
|
|
54
|
+
lidThickness: distance.optional(),
|
|
55
|
+
boardClearance: distance.optional(),
|
|
56
|
+
standoffHeight: distance.optional(),
|
|
57
|
+
topHeadroom: distance.optional(),
|
|
58
|
+
lidLipDepth: distance.optional(),
|
|
59
|
+
disableCutouts: z.boolean().optional(),
|
|
20
60
|
})
|
|
21
61
|
|
|
22
62
|
export type EnclosureFdmBoxPropsInput = z.input<typeof enclosureFdmBoxProps>
|