signal-layers 0.0.5 → 0.1.0

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/CheckBox.jsx CHANGED
@@ -1,149 +1,176 @@
1
- import { useState } from "react";
2
-
1
+ import { createSignalUtils } from "./";
3
2
  export function CheckBox(contract = {}) {
4
-
5
- const [inputSignal, layerSignal, dataSignal, stateSignal] = [{ ...contract }, {}, {}, {}];
6
- const checkboxId = `checkbox-${Math.random().toString(36).substring(2, 9)}`;
7
-
8
- const layer = (name, scope = "checkbox") => (className) =>
9
- (layerSignal[scope] ||= {},
10
- layerSignal[scope][name] ||= [],
11
- (layerSignal[scope][name][0] = className));
12
-
13
- const data = (name, key = name) =>
14
- inputSignal[key] !== undefined && (dataSignal[name] = inputSignal[key]);
15
-
16
- const state = (name, priority = 0, initial = false) => (
17
- (stateSignal._hooks ||= {})[name] ||= (() => {
18
- const [get, set] = useState(initial);
19
- return { get, set };
20
- })(),
21
- priority &&
22
- (!stateSignal._priority || priority > stateSignal._priority) &&
23
- (stateSignal[name] = stateSignal._hooks[name],
24
- stateSignal._priority = priority)
25
- );
26
-
27
- const classes = (layers = {}) =>
28
- Object.values(layers).map(l => l[0]).filter(Boolean).join(" ");
29
-
30
- let container, checkbox, label;
31
-
32
- container = {
33
- base: layer("base", "container"),
34
- color: layer("color", "container"),
35
- size: layer("size", "container"),
36
- layout: layer("layout", "container")
37
- }
38
-
39
- checkbox = {
40
- base: layer("base", "checkbox"),
41
- color: layer("color", "checkbox"),
42
- size: layer("size", "checkbox"),
43
- layout: layer("layout", "checkbox"),
44
- checked: layer("checked", "checkbox"),
45
- border: layer("border", "checkbox"),
46
- shape: layer("shape", "checkbox")
47
- }
48
-
49
- label = {
50
- base: layer("base", "label"),
51
- color: layer("color", "label"),
52
- font: layer("font", "label"),
53
- size: layer("size", "label"),
54
- layout: layer("layout", "label")
55
- }
3
+ const { layer, data, state, classes, signals } = createSignalUtils(contract);
4
+ const { inputSignal, layerSignal, dataSignal, stateSignal } = signals;
5
+ const checkboxId = `checkbox-${Math.random().toString(36).substring(2, 9)}`;
6
+ let container, checkbox, label;
7
+
8
+ container = {
9
+ base: layer("base", "container"),
10
+ color: layer("color", "container"),
11
+ size: layer("size", "container"),
12
+ layout: layer("layout", "container")
13
+ }
14
+
15
+ checkbox = {
16
+ base: layer("base", "checkbox"),
17
+ color: layer("color", "checkbox"),
18
+ size: layer("size", "checkbox"),
19
+ layout: layer("layout", "checkbox"),
20
+ checked: layer("checked", "checkbox"),
21
+ border: layer("border", "checkbox"),
22
+ shape: layer("shape", "checkbox"),
23
+ hover: layer("hover", "checkbox"),
24
+ focus: layer("focus", "checkbox"),
25
+ active: layer("active", "checkbox"),
26
+ interactive: layer("interactive", "checkbox")
27
+ }
28
+
29
+ label = {
30
+ base: layer("base", "label"),
31
+ color: layer("color", "label"),
32
+ font: layer("font", "label"),
33
+ size: layer("size", "label"),
34
+ layout: layer("layout", "label")
35
+ }
36
+
37
+ container.base("relative flex flex-row justify-center items-center");
38
+ container.color("bg-transparent");
39
+ container.size("h-3 w-3");
40
+ container.layout("gap-2");
41
+
42
+ checkbox.base("absolute inset-0 appearance-none cursor-pointer");
43
+ checkbox.color("border-gray-300 bg-transparent");
44
+ checkbox.size("h-3 w-3 checked:after:text-[8px]");
45
+ checkbox.border("border-2");
46
+ checkbox.shape("rounded-sm");
47
+ checkbox.layout("transition-all duration-200");
48
+ checkbox.checked(" checked:after:leading-none checked:border-blue-600 checked:bg-gray-300 checked:after:content-['✓'] checked:after:absolute checked:after:top-1/2 checked:after:left-1/2 checked:after:-translate-x-1/2 checked:after:-translate-y-1/2");
49
+
50
+ label.base("absolute cursor-pointer");
51
+ label.color("text-gray-800");
52
+ label.font("font-light");
53
+ label.size("text-sm");
54
+ label.layout("left-5");
55
+
56
+ inputSignal.primary && checkbox.color("border-blue-600 checked:bg-blue-50 checked:border-blue-600");
57
+ inputSignal.secondary && checkbox.color("border-gray-600 checked:bg-gray-50 checked:border-gray-600");
58
+ inputSignal.danger && checkbox.color("border-red-600 checked:bg-red-50 checked:border-red-600");
59
+ inputSignal.success && checkbox.color("border-green-600 checked:bg-green-50 checked:border-green-600");
60
+ inputSignal.warning && checkbox.color("border-yellow-600 checked:bg-yellow-50 checked:border-yellow-600");
61
+ inputSignal.info && checkbox.color("border-cyan-600 checked:bg-cyan-50 checked:border-cyan-600");
62
+ inputSignal.dark && checkbox.color("border-gray-600 checked:bg-gray-700 checked:border-gray-500");
63
+ inputSignal.light && checkbox.color("border-gray-300 checked:bg-gray-100 checked:border-gray-400");
64
+ inputSignal.neutral && checkbox.color("border-gray-400 checked:bg-gray-200 checked:border-gray-500");
65
+ inputSignal.brand && checkbox.color("border-brand-500 checked:bg-brand-50 checked:border-brand-600");
66
+ inputSignal.accent && checkbox.color("border-accent-500 checked:bg-accent-50 checked:border-accent-600");
67
+ inputSignal.ghost && checkbox.color("border-transparent bg-transparent checked:bg-transparent checked:border-transparent");
68
+ inputSignal.outline && checkbox.color("border-2 bg-transparent checked:bg-transparent");
69
+ inputSignal.filled && checkbox.color("border-transparent bg-gray-100 checked:bg-gray-200");
70
+ inputSignal.glass && checkbox.color("border-white/20 bg-white/10 backdrop-blur-sm checked:bg-white/20");
71
+ inputSignal.gradient && checkbox.color("border-transparent bg-linear-to-r from-blue-500 to-purple-500 checked:from-blue-600 checked:to-purple-600");
72
+ inputSignal.minimal && checkbox.color("border-gray-200 bg-transparent checked:border-gray-400 checked:bg-gray-50");
56
73
 
57
- container.base("relative");
58
- container.color("bg-transparent");
59
- container.size("h-3 w-3");
60
- container.layout("flex flex-row justify-center items-center");
61
-
62
- checkbox.base("absolute inset-0 appearance-none cursor-pointer");
63
- checkbox.color("border-gray-300 bg-transparent");
64
- checkbox.size("h-3 w-3 checked:after:text-[8px]");
65
- checkbox.border("border-2");
66
- checkbox.shape("rounded-sm");
67
- checkbox.layout("transition-all duration-200");
68
- checkbox.checked(" checked:after:leading-none checked:border-blue-600 checked:bg-gray-300 checked:after:content-['✓'] checked:after:absolute checked:after:top-1/2 checked:after:left-1/2 checked:after:-translate-x-1/2 checked:after:-translate-y-1/2");
69
-
70
- label.base("absolute cursor-pointer");
71
- label.color("text-gray-800");
72
- label.font("font-light");
73
- label.size("text-sm");
74
- label.layout("left-5");
75
-
76
-
77
- inputSignal.primary && checkbox.color("border-blue-600 checked:bg-blue-50 checked:border-blue-600");
78
- inputSignal.secondary && checkbox.color("border-gray-600 checked:bg-gray-50 checked:border-gray-600");
79
- inputSignal.danger && checkbox.color("border-red-600 checked:bg-red-50 checked:border-red-600");
80
- inputSignal.success && checkbox.color("border-green-600 checked:bg-green-50 checked:border-green-600");
81
- inputSignal.warning && checkbox.color("border-yellow-600 checked:bg-yellow-50 checked:border-yellow-600");
82
- inputSignal.info && checkbox.color("border-cyan-600 checked:bg-cyan-50 checked:border-cyan-600");
83
-
84
- inputSignal.square && checkbox.shape("rounded-none");
85
- inputSignal.rounded && checkbox.shape("rounded-sm");
86
- inputSignal.pill && checkbox.shape("rounded-full");
87
-
88
- inputSignal.hoverScale && checkbox.layout("hover:scale-105");
89
- inputSignal.pressShrink && checkbox.layout("active:scale-95");
90
- inputSignal.focusRing && checkbox.layout("focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1");
91
- inputSignal.noTransition && checkbox.layout("transition-none");
92
-
93
- inputSignal.loading && checkbox.color("opacity-50 cursor-wait");
94
- inputSignal.readonly && checkbox.color("cursor-not-allowed opacity-60");
95
- inputSignal.required && label.color("text-gray-900 font-medium");
96
-
97
- inputSignal.borderNone && checkbox.border("border-0");
98
- inputSignal.borderThick && checkbox.border("border-4");
99
- inputSignal.borderDashed && checkbox.border("border-2 border-dashed");
100
-
101
- inputSignal.xs && (label.size("text-xs"), container.size("h-2 w-2"), checkbox.size("h-2 w-2 checked:after:text-[4px]"));
102
- inputSignal.sm && (label.size("text-sm"), container.size("h-3 w-3"), checkbox.size("h-3 w-3 checked:after:text-[8px]"));
103
- inputSignal.md && (label.size("text-md"), container.size("h-4 w-4"), checkbox.size("h-4 w-4 checked:after:text-[10px]"));
104
- inputSignal.lg && (label.size("text-lg"), container.size("h-5 w-5"), checkbox.size("h-5 w-5 checked:after:text-[12px]"));
105
-
106
- inputSignal.labelLeft && label.layout("left-5");
107
- inputSignal.labelRight && label.layout("right-5");
108
- inputSignal.labelBottom && label.layout("top-5");
109
- inputSignal.labelTop && label.layout("bottom-5");
110
-
111
- inputSignal.label && data("label");
112
- inputSignal.checked && data("checked");
113
- inputSignal.defaultChecked && data("defaultChecked");
114
- inputSignal.onChange && data("onChange");
115
- inputSignal.disabled && data("disabled");
116
- inputSignal.ariaLabel && data("ariaLabel");
117
- inputSignal.ariaLabelledBy && data("ariaLabelledBy");
118
- inputSignal.ariaDescribedBy && data("ariaDescribedBy");
119
- inputSignal.ariaInvalid && data("ariaInvalid");
120
- state("checked", 1, 0);
121
-
122
- return (
123
- <div className={classes(layerSignal.container)}>
124
-
125
- <input
126
- type="checkbox"
127
- id={checkboxId}
128
- checked={dataSignal.checked ?? stateSignal.checked?.get}
129
- defaultChecked={dataSignal.defaultChecked}
130
- onChange={(e) => {
131
- const v = e.target.checked;
132
- stateSignal.checked?.set(v);
133
- dataSignal.onChange?.(v);
134
- }}
135
- disabled={dataSignal.disabled}
136
- aria-label={dataSignal.ariaLabel}
137
- aria-labelledby={dataSignal.ariaLabelledBy}
138
- aria-invalid={dataSignal.ariaInvalid}
139
- aria-describedby={dataSignal.ariaDescribedBy}
140
- className={`peer ${classes(layerSignal.checkbox)}`}
141
- />
142
-
143
-
144
74
 
145
- {dataSignal.label && (<label htmlFor={checkboxId} className={classes(layerSignal.label)}>{dataSignal.label}</label>)}
146
- </div>
75
+ inputSignal.square && checkbox.shape("rounded-none");
76
+ inputSignal.rounded && checkbox.shape("rounded-sm");
77
+ inputSignal.pill && checkbox.shape("rounded-full");
78
+
79
+ inputSignal.hoverScale && checkbox.hover("hover:scale-105");
80
+ inputSignal.pressShrink && checkbox.hover("active:scale-95");
81
+
82
+ inputSignal.focusRing && checkbox.focus("focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1");
83
+
84
+ inputSignal.loading && checkbox.interactive("opacity-50 cursor-wait");
85
+ inputSignal.readonly && checkbox.interactive("cursor-not-allowed opacity-60");
86
+
87
+ inputSignal.borderNone && checkbox.border("border-0");
88
+ inputSignal.borderThick && checkbox.border("border-4");
89
+ inputSignal.borderDashed && checkbox.border("border-2 border-dashed");
90
+
91
+ inputSignal.xs && (label.size("text-xs"), container.size("h-2 w-2"), checkbox.size("h-2 w-2 checked:after:text-[4px]"));
92
+ inputSignal.sm && (label.size("text-sm"), container.size("h-3 w-3"), checkbox.size("h-3 w-3 checked:after:text-[8px]"));
93
+ inputSignal.md && (label.size("text-md"), container.size("h-4 w-4"), checkbox.size("h-4 w-4 checked:after:text-[10px]"));
94
+ inputSignal.lg && (label.size("text-lg"), container.size("h-5 w-5"), checkbox.size("h-5 w-5 checked:after:text-[12px]"));
95
+
96
+ inputSignal.hoverGlow && checkbox.hover("hover:shadow-lg hover:shadow-blue-500/25");
97
+ inputSignal.hoverLift && checkbox.hover("hover:-translate-y-0.5 hover:shadow-md");
98
+ inputSignal.pressRotate && checkbox.active("active:rotate-90");
99
+ inputSignal.pressPulse && checkbox.active("active:animate-pulse");
100
+ inputSignal.focusGlow && checkbox.focus("focus:shadow-lg focus:shadow-blue-500/25");
101
+ inputSignal.focusScale && checkbox.focus("focus:scale-110");
102
+
103
+ inputSignal.labelLeft && label.layout("left-5");
104
+ inputSignal.labelRight && label.layout("right-5");
105
+ inputSignal.labelBottom && label.layout("top-5");
106
+ inputSignal.labelTop && label.layout("bottom-5");
107
+ inputSignal.labelStart && label.layout("left-5 rtl:right-5");
108
+ inputSignal.labelEnd && label.layout("right-5 rtl:left-5");
109
+
110
+ inputSignal.labelBold && label.font("font-bold");
111
+ inputSignal.labelSemibold && label.font("font-semibold");
112
+ inputSignal.labelMedium && label.font("font-medium");
113
+ inputSignal.labelRegular && label.font("font-normal");
114
+ inputSignal.labelLight && label.font("font-light");
115
+ inputSignal.labelThin && label.font("font-thin");
116
+
117
+ inputSignal.labelUppercase && label.font("uppercase");
118
+ inputSignal.labelLowercase && label.font("lowercase");
119
+ inputSignal.labelCapitalize && label.font("capitalize");
120
+
121
+ inputSignal.labelItalic && label.font("italic");
122
+ inputSignal.labelUnderline && label.font("underline");
123
+ inputSignal.labelLineThrough && label.font("line-through");
124
+
125
+ inputSignal.spaced && container.layout("space-x-2");
126
+ inputSignal.compact && container.layout("space-x-1");
127
+ inputSignal.tight && container.layout("gap-0");
128
+ inputSignal.snug && container.layout("gap-1");
129
+ inputSignal.normal && container.layout("gap-2");
130
+ inputSignal.relaxed && container.layout("gap-3");
131
+ inputSignal.loose && container.layout("gap-4");
132
+ inputSignal.extraLoose && container.layout("gap-6");
133
+
134
+ inputSignal.label && data("label");
135
+ inputSignal.checked && data("checked");
136
+ inputSignal.defaultChecked && data("defaultChecked");
137
+ inputSignal.onChange && data("onChange");
138
+ inputSignal.disabled && data("disabled");
139
+ inputSignal.ariaLabel && data("ariaLabel");
140
+ inputSignal.ariaLabelledBy && data("ariaLabelledBy");
141
+ inputSignal.ariaDescribedBy && data("ariaDescribedBy");
142
+ inputSignal.ariaInvalid && data("ariaInvalid");
143
+ inputSignal.name && data("name");
144
+ inputSignal.value && data("value");
145
+ inputSignal.form && data("form");
146
+ inputSignal.tabIndex && data("tabIndex");
147
+
148
+ state("checked", 1, 0);
149
+
150
+ return (
151
+ <div className={classes(layerSignal.container)}>
152
+
153
+ <input
154
+ type="checkbox"
155
+ id={checkboxId}
156
+ checked={dataSignal.checked ?? stateSignal.checked?.get}
157
+ defaultChecked={dataSignal.defaultChecked}
158
+ onChange={(e) => {
159
+ const v = e.target.checked;
160
+ stateSignal.checked?.set(v);
161
+ dataSignal.onChange?.(v);
162
+ }}
163
+ disabled={dataSignal.disabled}
164
+ aria-label={dataSignal.ariaLabel}
165
+ aria-labelledby={dataSignal.ariaLabelledBy}
166
+ aria-invalid={dataSignal.ariaInvalid}
167
+ aria-describedby={dataSignal.ariaDescribedBy}
168
+ className={`peer ${classes(layerSignal.checkbox)}`}
169
+ />
170
+
171
+ {dataSignal.label && (<label htmlFor={checkboxId} className={classes(layerSignal.label)}>{dataSignal.label}</label>)}
172
+
173
+ </div>
147
174
  )
148
175
 
149
176
  }
package/src/Dropdown.jsx CHANGED
@@ -1,198 +1,91 @@
1
- import { Button } from "./Button";
2
- import { useState } from "react";
3
-
1
+ import { Button, createSignalUtils } from "./";
4
2
  export function Dropdown(contract = {}) {
5
- /* ────────────────────────────────────────────────────────────────────────────
6
- * CONTRACT
7
- * ────────────────────────────────────────────────────────────────────────────
8
- *
9
- * Foundation: Button trigger with dropdown menu list
10
- *
11
- * Signals:
12
- * Position: top, bottom, left, right
13
- * Align: start, center, end
14
- * Size: xs, sm, md, lg
15
- * Layout: inline, block, centered
16
- * State: disabled
17
- * Interaction: reactClick, reactHover
18
- *
19
- * Data:
20
- * menuName - Text for trigger button
21
- * items - Array of {label, onClick, href?} objects
22
- * onItemSelect - Callback when item selected
23
- * onMenuClick - Callback when menu clicked
24
- *
25
- * Defaults: bottom, start, sm, inline, reactClick
26
- *
27
- * Usage:
28
- * <Dropdown menuName="Menu" items={[{label:"Item 1", onClick:() => {}}]} />
29
- *
30
- * ──────────────────────────────────────────────────────────────────────────── */
3
+ const { layer, data, state, classes, signals } = createSignalUtils(contract);
4
+ const { inputSignal, layerSignal, dataSignal, stateSignal } = signals;
5
+ let root, trigger, menu, item;
6
+ root = {
7
+ base: layer("base", "root"),
8
+ layout: layer("layout", "root"),
9
+ };
31
10
 
32
- const [inputSignal, layerSignal, dataSignal, stateSignal] = [{ ...contract }, {}, {}, {}];
11
+ trigger = {
12
+ base: layer("base", "trigger"),
13
+ layout: layer("layout", "trigger"),
14
+ };
33
15
 
34
- /* ────────────────────────────────────────────────────────────────────────────
35
- * CONTRACT TOOLS
36
- * ──────────────────────────────────────────────────────────────────────────── */
37
- const layer = (name,scope = "root") => (className) =>
38
- (layerSignal[scope] ||= {},
39
- layerSignal[scope][name] ||= [],
40
- (layerSignal[scope][name][0] = className));
16
+ menu = {
17
+ base: layer("base", "menu"),
18
+ size: layer("size", "menu"),
19
+ layout: layer("layout", "menu"),
20
+ shape: layer("shape", "menu"),
21
+ shadow: layer("shadow", "menu"),
22
+ color: layer("color", "menu"),
23
+ position: layer("position", "menu"),
24
+ animation: layer("animation", "menu"),
25
+ visibility: layer("visibility", "menu"),
26
+ };
41
27
 
42
- const data = (name, key = name) =>
43
- inputSignal[key] && (dataSignal[name] = inputSignal[key]);
28
+ item = {
29
+ base: layer("base", "item"),
30
+ hover: layer("hover", "item"),
31
+ };
44
32
 
45
- const state = (name, priority = 0) => (
46
- (stateSignal._hooks ||= {})[name] ||= (() => { const [get, set] = useState(false); return ({ get, set }); })(),
47
- priority && (!stateSignal._priority || priority > stateSignal._priority) && (stateSignal[name] = stateSignal._hooks[name], stateSignal._priority = priority)
48
- );
33
+ root.base("relative");
34
+ root.layout("inline-block");
35
+ trigger.base("cursor-pointer select-none");
36
+ menu.base("absolute z-50");
37
+ menu.layout("flex flex-col");
38
+ menu.shape("rounded-lg");
39
+ menu.shadow("shadow-lg");
40
+ menu.color("bg-white/90 text-gray-800");
41
+ menu.visibility("opacity-100 pointer-events-auto");
42
+ menu.animation("transition-all duration-200");
43
+ menu.position("top-full left-0 mt-2");
44
+ menu.size("min-w-40 text-sm");
45
+ item.base("px-4 py-2 whitespace-nowrap");
46
+ item.hover("hover:bg-gray-100 hover:rounded-lg cursor-pointer");
47
+
48
+ inputSignal.bottom && menu.position("top-full left-0 mt-2");
49
+ inputSignal.top && menu.position("bottom-full left-0 mb-2");
50
+ inputSignal.right && menu.position("left-full top-0 ml-2");
51
+ inputSignal.left && menu.position("right-full top-0 mr-2");
52
+ inputSignal.start && menu.position("left-0");
53
+ inputSignal.center && menu.position("left-1/2 -translate-x-1/2");
54
+ inputSignal.end && menu.position("right-0");
55
+
56
+ inputSignal.xs && menu.size("min-w-28 text-xs");
57
+ inputSignal.sm && menu.size("min-w-36 text-sm");
58
+ inputSignal.md && menu.size("min-w-44 text-base");
59
+ inputSignal.lg && menu.size("min-w-56 text-lg");
60
+ inputSignal.xl && menu.size("min-w-64 text-xl");
49
61
 
50
- const classes = (layers = {}) =>
51
- Object.values(layers).map(l => l[0]).filter(Boolean).join(" ");
62
+ inputSignal.block && root.layout("block w-full");
63
+ inputSignal.inline && root.layout("inline-block");
64
+ inputSignal.centered && root.layout("mx-auto");
65
+
66
+ inputSignal.disabled && (trigger.base("opacity-50 pointer-events-none"), menu.visibility("hidden"));
67
+
68
+ inputSignal.items && data("items");
69
+ inputSignal.menuName && data("menuName");
70
+ inputSignal.onItemSelect && data("onItemSelect");
71
+ inputSignal.onMenuClick && data("onMenuClick");
72
+ state("reactHover", 0);
73
+ state("reactClick", 0);
74
+ inputSignal.reactHover && state("reactHover", 1);
75
+ state("reactClick", 1);
52
76
 
53
- /* ────────────────────────────────────────────────────────────────────────────
54
- * BASE LAYERS
55
- * ──────────────────────────────────────────────────────────────────────────── */
56
- let root, trigger, menu, item;
57
- (() =>
58
- (
59
- root = {
60
- base: layer("base", "root"),
61
- layout: layer("layout", "root")
62
- }
63
- )
64
- )(),
65
- (() =>
66
- (
67
- trigger = {
68
- base: layer("base", "trigger"),
69
- layout: layer("layout", "trigger")
70
- }
71
- )
72
- )(),
73
- (() =>
74
- (
75
- menu = {
76
- base: layer("base", "menu"),
77
- size: layer("size", "menu"),
78
- layout: layer("layout", "menu"),
79
- shape: layer("shape", "menu"),
80
- shadow: layer("shadow", "menu"),
81
- color: layer("color", "menu"),
82
- position: layer("position", "menu"),
83
- animation: layer("animation", "menu"),
84
- visibility: layer("visibility", "menu")
85
- }
86
- )
87
- )(),
88
- (() =>
89
- (
90
- item = {
91
- base: layer("base", "item"),
92
- hover: layer("hover", "item")
93
- }
94
- )
95
- )(),
96
- /* ────────────────────────────────────────────────────────────────────────────
97
- * DEFAULTS
98
- * ──────────────────────────────────────────────────────────────────────────── */
99
- (() =>
100
- (
101
- root.base("relative"),
102
- root.layout("inline-block"),
103
- trigger.base("cursor-pointer select-none"),
104
- menu.base("absolute z-50"),
105
- menu.layout("flex flex-col"),
106
- menu.shape("rounded-lg"),
107
- menu.shadow("shadow-lg"),
108
- menu.color("bg-white/90 text-gray-800"),
109
- menu.visibility("opacity-100 pointer-events-auto"),
110
- menu.animation("transition-all duration-200"),
111
- menu.position("top-full left-0 mt-2"),
112
- menu.size("min-w-40 text-sm"),
113
- item.base("px-4 py-2 whitespace-nowrap"),
114
- item.hover("hover:bg-gray-100 hover:rounded-lg cursor-pointer")
115
- )
116
- )(),
117
- /* ────────────────────────────────────────────────────────────────────────────
118
- * MENU POSITION SIGNALS
119
- * ──────────────────────────────────────────────────────────────────────────── */
120
- (()=>
121
- (
122
- inputSignal.bottom && menu.position("top-full left-0 mt-2"),
123
- inputSignal.top && menu.position("bottom-full left-0 mb-2"),
124
- inputSignal.right && menu.position("left-full top-0 ml-2"),
125
- inputSignal.left && menu.position("right-full top-0 mr-2"),
126
- inputSignal.start && menu.position("left-0"),
127
- inputSignal.center && menu.position("left-1/2 -translate-x-1/2"),
128
- inputSignal.end && menu.position("right-0")
129
- )
130
- )(),
131
- /* ────────────────────────────────────────────────────────────────────────────
132
- * MENU SIZE SIGNALS
133
- * ──────────────────────────────────────────────────────────────────────────── */
134
- (()=>
135
- (
136
- inputSignal.xs && menu.size("min-w-28 text-xs"),
137
- inputSignal.sm && menu.size("min-w-36 text-sm"),
138
- inputSignal.md && menu.size("min-w-44 text-base"),
139
- inputSignal.lg && menu.size("min-w-56 text-lg"),
140
- inputSignal.xl && menu.size("min-w-64 text-xl")
141
- )
142
- )(),
143
- /* ────────────────────────────────────────────────────────────────────────────
144
- * MENU LAYOUT SIGNALS
145
- * ──────────────────────────────────────────────────────────────────────────── */
146
- (()=>
147
- (
148
- inputSignal.block && root.layout("block w-full"),
149
- inputSignal.inline && root.layout("inline-block"),
150
- inputSignal.centered && root.layout("mx-auto")
151
- )
152
- )(),
153
- /* ────────────────────────────────────────────────────────────────────────────
154
- * MENU VISIBILITY SIGNALS
155
- * ──────────────────────────────────────────────────────────────────────────── */
156
- (()=>
157
- (
158
- inputSignal.disabled && (
159
- trigger.base("opacity-50 pointer-events-none"),
160
- menu.visibility("hidden")
161
- )
162
- )
163
- )(),
164
- /* ────────────────────────────────────────────────────────────────────────────
165
- * DATA & STATE
166
- * ──────────────────────────────────────────────────────────────────────────── */
167
- (()=>
168
- (
169
- inputSignal.items && data("items"),
170
- inputSignal.menuName && data("menuName"),
171
- inputSignal.onItemSelect && data("onItemSelect"),
172
- inputSignal.onMenuClick && data("onMenuClick"),
173
- state("reactHover", 0), state("reactClick", 0),
174
- inputSignal.reactHover && state("reactHover", 1),
175
- state("reactClick", 1)
176
- )
177
- )();
178
- /* ────────────────────────────────────────────────────────────────────────────
179
- * INTERNAL COMPONENTS
180
- * ──────────────────────────────────────────────────────────────────────────── */
181
77
  const DropdownItem = ({ item }) => (
182
- <div
183
- className={classes(layerSignal.item)}
184
- onClick={() => {
185
- stateSignal.reactClick?.set && stateSignal.reactClick.set(false);
186
- dataSignal.onItemSelect?.(item)
187
- }}
188
- {...(item.href ? { href: item.href, onClick: e => e.stopPropagation() } : {})}
189
- >
190
- {item.label}
191
- </div>
78
+ <div
79
+ className={classes(layerSignal.item)}
80
+ onClick={() => {
81
+ stateSignal.reactClick?.set && stateSignal.reactClick.set(false);
82
+ dataSignal.onItemSelect?.(item)
83
+ }}
84
+ {...(item.href ? { href: item.href, onClick: e => e.stopPropagation() } : {})}
85
+ >
86
+ {item.label}
87
+ </div>
192
88
  );
193
- /* ────────────────────────────────────────────────────────────────────────────
194
- * RENDER
195
- * ──────────────────────────────────────────────────────────────────────────── */
196
89
 
197
90
  return (
198
91
  <div className={classes(layerSignal.root)}>