signal-layers 0.0.6 → 0.1.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/src/Card.jsx CHANGED
@@ -1,257 +1,166 @@
1
- import {Button} from "./Button";
2
-
1
+ import { Button } from "./";
3
2
  export function Card(contract = {}) {
4
- /* ────────────────────────────────────────────────────────────────────────────
5
- * CONTRACT
6
- * ────────────────────────────────────────────────────────────────────────────
7
- *
8
- * Card - Content container with optional image, text, and action button
9
- *
10
- * Foundation: Structured layout with image, body, and action sections
11
- *
12
- * Signals:
13
- * Size: xs, sm, md, lg, xl
14
- * Layout: centered, rightAligned, leftAligned
15
- * Image: imageCircle, imageLandscape
16
- * Style: transparent
17
- * Interaction: interactive
18
- *
19
- * Data:
20
- * image - Image URL or source
21
- * imageName - Alt text for image
22
- * title - Card title text
23
- * description - Card description text
24
- * buttonLabel - Button text
25
- * onButtonClick - Button click handler
26
- *
27
- * Defaults: md, leftAligned
28
- *
29
- * Usage:
30
- * <Card title="Title" description="Description" />
31
- * <Card image="url.jpg" title="Title" interactive lg />
32
- * <Card centered transparent buttonLabel="Action" onButtonClick={() => {}} />
33
- *
34
- * ──────────────────────────────────────────────────────────────────────────── */
35
-
36
- const [inputSignal, layerSignal, dataSignal] = [{ ...contract }, {}, {}];
37
-
38
- /* ────────────────────────────────────────────────────────────────────────────
39
- * CONTRACT TOOLS
40
- * ──────────────────────────────────────────────────────────────────────────── */
41
-
42
- const layer = (name, scope = "card") => (className) =>
43
- (layerSignal[scope] ||= {},
44
- layerSignal[scope][name] ||= [],
45
- (layerSignal[scope][name][0] = className));
46
-
47
- const data = (name, key = name) =>
48
- inputSignal[key] && (dataSignal[name] = inputSignal[key]);
49
-
50
- const classes = (layers = {}) =>
51
- Object.values(layers).map(l => l[0]).filter(Boolean).join(" ");
52
-
53
- /* ────────────────────────────────────────────────────────────────────────────
54
- * BASE LAYERS
55
- * ──────────────────────────────────────────────────────────────────────────── */
56
- let card, image, title, description, button;
57
- (() =>
58
- (
59
- card = {
60
- base:layer("base", "card"),
61
- layout:layer("layout", "card"),
62
- spacing:layer("spacing", "card"),
63
- border:layer("border", "card"),
64
- shadow:layer("shadow", "card"),
65
- hover:layer("hover", "card"),
66
- animation:layer("animation","card")
67
- }
68
- )
69
- )(),
70
- (() =>
71
- (
72
- image = {
73
- base:layer("base", "image"),
74
- size:layer("size", "image"),
75
- aspect:layer("aspect", "image")
76
- }
77
- )
78
- )(),
79
- (() =>
80
- (
81
- title = {
82
- base:layer("base", "title"),
83
- size:layer("size", "title"),
84
- layout:layer("layout", "title")
85
- }
86
- )
87
- )(),
88
- (() =>
89
- (
90
- description = {
91
- base:layer("base", "description"),
92
- size:layer("size", "description"),
93
- layout:layer("layout", "description")
94
- }
95
- )
96
- )(),
97
- (() =>
98
- (
99
- button = {
100
- base:layer("base", "button")
101
- }
102
- )
103
- )(),
104
- /* ────────────────────────────────────────────────────────────────────────────
105
- * DEFAULTS
106
- * ──────────────────────────────────────────────────────────────────────────── */
107
- (() =>
108
- (
109
- card.border("border-0"),
110
- card.spacing("p-0 gap-4"),
111
- card.hover("hover:scale-100"),
112
- card.shadow("shadow-2xl shadow-gray-800/80"),
113
- card.animation("transition-all duration-300"),
114
- card.base("bg-gray-800 text-white rounded-lg"),
115
- card.layout("flex flex-col justify-items-start"),
116
- image.base("rounded-lg object-cover"),
117
- image.size("w-full h-auto"),
118
- image.aspect("aspect-auto"),
119
- title.base("font-light font-sans font-stretch-condensed px-4 py-0"),
120
- title.layout("text-left"),
121
- title.size("text-lg"),
122
- description.base("font-light font-sans font-stretch-condensed px-4 py-0"),
123
- description.layout("text-left"),
124
- description.size("text-lg"),
125
- button.base("font-sans mb-2 cursor-pointer")
126
- )
127
- )(),
128
- /* ────────────────────────────────────────────────────────────────────────────
129
- * INTERACTIVE SIGNAL
130
- * ──────────────────────────────────────────────────────────────────────────── */
131
- (() =>
132
- (
133
- inputSignal.interactive && card.hover("cursor-pointer hover:scale-[1.02]")
134
- )
135
- )(),
136
- /* ────────────────────────────────────────────────────────────────────────────
137
- * SIZE SIGNALS
138
- * ──────────────────────────────────────────────────────────────────────────── */
139
- (() =>
140
- (
141
- inputSignal.xs && (
142
- title.size("text-md"),
143
- description.size("text-xs"),
144
- card.spacing("gap-2"),
145
- image.size("w-auto h-24")
146
- ),
147
-
148
- inputSignal.sm && (
149
- title.size("text-lg"),
150
- description.size("text-md"),
151
- card.spacing("gap-4"),
152
- image.size("w-auto h-32")
153
- ),
154
-
155
- inputSignal.md && (
156
- title.size("text-2xl"),
157
- description.size("text-lg"),
158
- card.spacing("gap-6"),
159
- image.size("w-auto h-48")
160
- ),
161
-
162
- inputSignal.lg && (
163
- title.size("text-3xl"),
164
- description.size("text-xl"),
165
- card.spacing("gap-8"),
166
- image.size("w-auto h-64")
167
- ),
168
-
169
- inputSignal.xl && (
170
- title.size("text-4xl"),
171
- description.size("text-2xl"),
172
- card.spacing("gap-10"),
173
- image.size("w-auto h-96")
174
- )
175
- )
176
- )(),
177
- /* ────────────────────────────────────────────────────────────────────────────
178
- * LAYOUT SIGNALS
179
- * ──────────────────────────────────────────────────────────────────────────── */
180
- (() =>
181
- (
182
- inputSignal.centered && (
183
- title.layout("text-center"),
184
- description.layout("text-center")
185
- ),
186
-
187
- inputSignal.rightAligned && (
188
- title.layout("text-right"),
189
- description.layout("text-right")
190
- ),
191
-
192
- inputSignal.leftAligned && (
193
- title.layout("text-left"),
194
- description.layout("text-left")
195
- ),
196
-
197
- inputSignal.imageCircle && (
198
- image.base("rounded-full aspect-square p-0 object-cover"),
199
- card.layout("flex flex-col justify-center items-center")
200
- ),
201
-
202
- inputSignal.imageLandscape && (
203
- image.aspect("aspect-video")
204
- ),
205
-
206
- inputSignal.transparent && (
207
- card.base("bg-transparent"),
208
- card.shadow("shadow-none")
209
- )
210
- )
211
- )(),
212
- /* ────────────────────────────────────────────────────────────────────────────
213
- * DATA
214
- * ──────────────────────────────────────────────────────────────────────────── */
215
- (() =>
216
- (
217
- inputSignal.image && data("image"),
218
- inputSignal.imageName && data("imageName"),
219
- inputSignal.title && data("title"),
220
- inputSignal.description && data("description"),
221
- inputSignal.buttonLabel && data("buttonLabel"),
222
- inputSignal.onButtonClick && data("onButtonClick")
223
- )
224
- )();
225
- /* ──────────────────────────────────────────────────────────────────────────────
226
- * INTERNAL COMPONENTS
227
- * ────────────────────────────────────────────────────────────────────────────── */
228
-
229
- const CardMedia = ({ image, imageName, layers }) =>
230
- image ? <img src={image} className={classes(layers)} alt={imageName} loading="lazy" decoding="async"/> : null;
231
-
232
- const CardBody = ({ title, description, titleLayers, descriptionLayers }) =>
233
- <>{title && <h3 className={classes(titleLayers)}>{title}</h3>}{description && <p className={classes(descriptionLayers)}>{description}</p>}</>;
234
-
235
- const CardActions = ({ label, onBtnClick, layers }) =>
236
- <>{label && <Button rounded md border innerShadow hoverNone activeNone className={classes(layers)} onClick={onBtnClick}>{label}</Button>}</>;
3
+ const { layer, data, state, classes, signals } = createSignalUtils(contract);
4
+ const { inputSignal, layerSignal, dataSignal } = signals;
5
+ let card, image, title, description, button;
6
+
7
+ card = {
8
+ base: layer("base", "card"),
9
+ layout: layer("layout", "card"),
10
+ spacing: layer("spacing", "card"),
11
+ border: layer("border", "card"),
12
+ shadow: layer("shadow", "card"),
13
+ hover: layer("hover", "card"),
14
+ animation: layer("animation", "card")
15
+ };
16
+
17
+ image = {
18
+ base: layer("base", "image"),
19
+ size: layer("size", "image"),
20
+ aspect: layer("aspect", "image")
21
+ };
22
+
23
+ title = {
24
+ base: layer("base", "title"),
25
+ size: layer("size", "title"),
26
+ layout: layer("layout", "title")
27
+ };
28
+
29
+ description = {
30
+ base: layer("base", "description"),
31
+ size: layer("size", "description"),
32
+ layout: layer("layout", "description")
33
+ };
34
+
35
+ button = {
36
+ base: layer("base", "button")
37
+ };
38
+
39
+ card.border("border-0");
40
+ card.spacing("p-0 gap-4");
41
+ card.hover("hover:scale-100");
42
+ card.shadow("shadow-2xl shadow-gray-800/80");
43
+ card.animation("transition-all duration-300");
44
+ card.base("bg-gray-800 text-white rounded-lg");
45
+ card.layout("flex flex-col justify-items-start");
46
+ image.base("rounded-lg object-cover");
47
+ image.size("w-full h-auto");
48
+ image.aspect("aspect-auto");
49
+ title.base("font-light font-sans font-stretch-condensed px-4 py-0");
50
+ title.layout("text-left");
51
+ title.size("text-lg");
52
+ description.base("font-light font-sans font-stretch-condensed px-4 py-0");
53
+ description.layout("text-left");
54
+ description.size("text-lg");
55
+ button.base("font-sans mb-2 cursor-pointer");
56
+
57
+ inputSignal.interactive && card.hover("cursor-pointer hover:scale-[1.02]");
58
+
59
+ inputSignal.xs &&
60
+ (title.size("text-md"),
61
+ description.size("text-xs"),
62
+ card.spacing("gap-2"),
63
+ image.size("w-auto h-24"));
64
+
65
+ inputSignal.sm &&
66
+ (title.size("text-lg"),
67
+ description.size("text-md"),
68
+ card.spacing("gap-4"),
69
+ image.size("w-auto h-32"));
70
+
71
+ inputSignal.md &&
72
+ (title.size("text-2xl"),
73
+ description.size("text-lg"),
74
+ card.spacing("gap-6"),
75
+ image.size("w-auto h-48"));
76
+
77
+ inputSignal.lg &&
78
+ (title.size("text-3xl"),
79
+ description.size("text-xl"),
80
+ card.spacing("gap-8"),
81
+ image.size("w-auto h-64"));
82
+
83
+ inputSignal.xl &&
84
+ (title.size("text-4xl"),
85
+ description.size("text-2xl"),
86
+ card.spacing("gap-10"),
87
+ image.size("w-auto h-96"));
88
+
89
+ inputSignal.centered &&
90
+ (title.layout("text-center"), description.layout("text-center"));
91
+
92
+ inputSignal.rightAligned &&
93
+ (title.layout("text-right"), description.layout("text-right"));
94
+
95
+ inputSignal.leftAligned &&
96
+ (title.layout("text-left"), description.layout("text-left"));
97
+
98
+ inputSignal.imageCircle &&
99
+ (image.base("rounded-full aspect-square p-0 object-cover"),
100
+ card.layout("flex flex-col justify-center items-center"));
101
+
102
+ inputSignal.imageLandscape && image.aspect("aspect-video");
103
+
104
+ inputSignal.transparent &&
105
+ (card.base("bg-transparent"), card.shadow("shadow-none"));
106
+
107
+ inputSignal.image && data("image");
108
+ inputSignal.imageName && data("imageName");
109
+ inputSignal.title && data("title");
110
+ inputSignal.description && data("description");
111
+ inputSignal.buttonLabel && data("buttonLabel");
112
+ inputSignal.onButtonClick && data("onButtonClick");
113
+
114
+ const CardMedia = ({ image, imageName, layers }) =>
115
+ image ? (
116
+ <img
117
+ src={image}
118
+ className={classes(layers)}
119
+ alt={imageName}
120
+ loading="lazy"
121
+ decoding="async"
122
+ />
123
+ ) : null;
124
+
125
+ const CardBody = ({ title, description, titleLayers, descriptionLayers }) => (
126
+ <>
127
+ {title && <h3 className={classes(titleLayers)}>{title}</h3>}
128
+ {description && (
129
+ <p className={classes(descriptionLayers)}>{description}</p>
130
+ )}
131
+ </>
132
+ );
237
133
 
238
- const CardShell = ({ layers, children }) =>
239
- <div className={classes(layers)}>{children}</div>;
134
+ const CardActions = ({ label, onBtnClick, layers }) => (
135
+ <>
136
+ {label && (
137
+ <Button
138
+ rounded
139
+ md
140
+ border
141
+ innerShadow
142
+ hoverNone
143
+ activeNone
144
+ className={classes(layers)}
145
+ onClick={onBtnClick}
146
+ >
147
+ {label}
148
+ </Button>
149
+ )}
150
+ </>
151
+ );
240
152
 
241
- /* ────────────────────────────────────────────────────────────────────────────
242
- * RENDER
243
- * ──────────────────────────────────────────────────────────────────────────── */
153
+ const CardShell = ({ layers, children }) => (
154
+ <div className={classes(layers)}>{children}</div>
155
+ );
244
156
 
245
157
  return (
246
- <CardShell
247
- layers={layerSignal.card}
248
- >
249
-
158
+ <CardShell layers={layerSignal.card}>
250
159
  {dataSignal.image && (
251
- <CardMedia
160
+ <CardMedia
252
161
  image={dataSignal.image}
253
- imageName={dataSignal.imageName}
254
- layers={layerSignal.image}
162
+ imageName={dataSignal.imageName}
163
+ layers={layerSignal.image}
255
164
  />
256
165
  )}
257
166
 
@@ -271,7 +180,6 @@ export function Card(contract = {}) {
271
180
  onBtnClick={dataSignal.onButtonClick}
272
181
  />
273
182
  )}
274
-
275
183
  </CardShell>
276
184
  );
277
- }
185
+ }