@ailuracode/alpine-toggle 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) ailuracode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # @ailuracode/alpine-toggle
2
+
3
+ Alpine.js magic for **binary** and **ternary** toggles with full TypeScript inference.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @ailuracode/alpine-toggle alpinejs
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```js
14
+ import Alpine from "alpinejs";
15
+ import toggle from "@ailuracode/alpine-toggle";
16
+
17
+ Alpine.plugin(toggle);
18
+ Alpine.start();
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Each call to `$toggle()` returns an independent reactive instance.
24
+
25
+ ### Binary (two opposite states)
26
+
27
+ ```html
28
+ <div x-data="{ power: $toggle({ states: { truly: 'on', falsely: 'off' }, initial: 'off' }) }">
29
+ <p x-text="power.value"></p>
30
+ <button type="button" @click="power.toggle()">Toggle</button>
31
+ </div>
32
+ ```
33
+
34
+ ```ts
35
+ const power = createToggle({ states: { truly: "on", falsely: "off" } });
36
+ power.ternary; // undefined
37
+ ```
38
+
39
+ ### Ternary (two opposites + one independent state)
40
+
41
+ The third state is **independent** — `toggle()` only flips between `truly` and `falsely`. Use `cycle()` to visit all three.
42
+
43
+ ```html
44
+ <div x-data="{ answer: $toggle({
45
+ states: { truly: 'yes', falsely: 'no', ternary: 'unknown' },
46
+ initial: 'unknown',
47
+ }) }">
48
+ <p>
49
+ Value: <strong x-text="answer.value"></strong>
50
+ <span x-show="answer.is(answer.ternary)" class="badge">neutral</span>
51
+ </p>
52
+ <button type="button" @click="answer.toggle()">Yes / No</button>
53
+ <button type="button" @click="answer.cycle()">Cycle all</button>
54
+ <button type="button" @click="answer.set(answer.ternary)">Reset to unknown</button>
55
+ </div>
56
+ ```
57
+
58
+ ```ts
59
+ const answer = createToggle({
60
+ states: { truly: "yes", falsely: "no", ternary: "unknown" },
61
+ });
62
+ ```
63
+
64
+ Without `states.ternary`, the property defaults to `undefined`:
65
+
66
+ ```ts
67
+ const power = createToggle({ states: { truly: "on", falsely: "off" } });
68
+ power.ternary; // undefined
69
+ ```
70
+
71
+ ## API
72
+
73
+ ### Options
74
+
75
+ | Option | Type | Description |
76
+ |--------|------|-------------|
77
+ | `states.truly` | `TA` | First opposite state |
78
+ | `states.falsely` | `TB` | Second opposite state |
79
+ | `states.ternary` | `TN` | Optional independent state (`undefined` by default) |
80
+ | `initial` | value | Starting value (default: `truly`, or `ternary` when configured) |
81
+
82
+ ### Instance
83
+
84
+ | Member | Description |
85
+ |--------|-------------|
86
+ | `value` | Current state |
87
+ | `states` | Readonly object `{ truly, falsely, ternary }` |
88
+ | `truly` / `falsely` / `ternary` | Shorthand for `states.*` |
89
+ | `is(value)` | Whether `value` is active |
90
+ | `set(value)` | Set state; returns `false` if unchanged or invalid |
91
+ | `toggle()` | Flip between opposites (from ternary → `truly`) |
92
+ | `cycle()` | Advance to the next state in order |
93
+ | `reset()` | Restore `initial` |
94
+
95
+ ## Types
96
+
97
+ ```ts
98
+ import { createToggle, type ToggleValue } from "@ailuracode/alpine-toggle";
99
+
100
+ type OnOff = ToggleValue<"on", "off">;
101
+ type Answer = ToggleValue<"yes", "no", "unknown">;
102
+ ```
103
+
104
+ Add `/// <reference path="node_modules/@ailuracode/alpine-toggle/dist/global.d.ts" />` for `$toggle` in templates.
105
+
106
+ ## License
107
+
108
+ MIT
@@ -0,0 +1,49 @@
1
+ /// <reference types="@types/alpinejs" />
2
+
3
+ export interface ToggleBinaryStates<TA, TB> {
4
+ truly: TA;
5
+ falsely: TB;
6
+ }
7
+
8
+ export interface ToggleTernaryStates<TA, TB, TN> extends ToggleBinaryStates<TA, TB> {
9
+ ternary: TN;
10
+ }
11
+
12
+ export type ToggleValue<TA, TB, TN = undefined> = TN extends undefined ? TA | TB : TA | TB | TN;
13
+
14
+ export interface ToggleOptions<TA, TB, TN = undefined> {
15
+ states: ToggleBinaryStates<TA, TB> & { ternary?: TN };
16
+ initial?: TA | TB | TN;
17
+ }
18
+
19
+ export interface ToggleInstance<TA, TB, TN, V> {
20
+ value: V;
21
+ readonly states: ToggleBinaryStates<TA, TB> & { ternary: TN };
22
+ readonly truly: TA;
23
+ readonly falsely: TB;
24
+ readonly ternary: TN;
25
+ is(value: V): boolean;
26
+ set(value: V): boolean;
27
+ toggle(): V;
28
+ cycle(): V;
29
+ reset(): V;
30
+ }
31
+
32
+ export type ToggleMagic = {
33
+ <const TA, const TB>(options: {
34
+ states: ToggleBinaryStates<TA, TB>;
35
+ initial?: TA | TB;
36
+ }): ToggleInstance<TA, TB, undefined, TA | TB>;
37
+ <const TA, const TB, const TN>(options: {
38
+ states: ToggleTernaryStates<TA, TB, TN>;
39
+ initial?: TA | TB | TN;
40
+ }): ToggleInstance<TA, TB, TN, TA | TB | TN>;
41
+ };
42
+
43
+ declare global {
44
+ namespace Alpine {
45
+ interface Magics<T> {
46
+ $toggle: ToggleMagic;
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,55 @@
1
+ import AlpineType from 'alpinejs';
2
+
3
+ interface ToggleBinaryStates<TA, TB> {
4
+ truly: TA;
5
+ falsely: TB;
6
+ }
7
+ interface ToggleTernaryStates<TA, TB, TN> extends ToggleBinaryStates<TA, TB> {
8
+ ternary: TN;
9
+ }
10
+ type ToggleValue<TA, TB, TN = undefined> = TN extends undefined ? TA | TB : TA | TB | TN;
11
+ interface ToggleOptions<TA, TB, TN = undefined> {
12
+ states: ToggleBinaryStates<TA, TB> & {
13
+ ternary?: TN;
14
+ };
15
+ initial?: TA | TB | TN;
16
+ }
17
+ interface ToggleInstance<TA, TB, TN, V> {
18
+ value: V;
19
+ readonly states: ToggleBinaryStates<TA, TB> & {
20
+ ternary: TN;
21
+ };
22
+ readonly truly: TA;
23
+ readonly falsely: TB;
24
+ readonly ternary: TN;
25
+ is(value: V): boolean;
26
+ set(value: V): boolean;
27
+ toggle(): V;
28
+ cycle(): V;
29
+ reset(): V;
30
+ }
31
+ type ToggleMagic = {
32
+ <const TA, const TB>(options: {
33
+ states: ToggleBinaryStates<TA, TB>;
34
+ initial?: TA | TB;
35
+ }): ToggleInstance<TA, TB, undefined, TA | TB>;
36
+ <const TA, const TB, const TN>(options: {
37
+ states: ToggleTernaryStates<TA, TB, TN>;
38
+ initial?: TA | TB | TN;
39
+ }): ToggleInstance<TA, TB, TN, TA | TB | TN>;
40
+ };
41
+ /** Creates an independent toggle instance with optional ternary state. */
42
+ declare function createToggle<const TA, const TB>(options: {
43
+ states: ToggleBinaryStates<TA, TB>;
44
+ initial?: TA | TB;
45
+ }): ToggleInstance<TA, TB, undefined, TA | TB>;
46
+ declare function createToggle<const TA, const TB, const TN>(options: {
47
+ states: ToggleTernaryStates<TA, TB, TN>;
48
+ initial?: TA | TB | TN;
49
+ }): ToggleInstance<TA, TB, TN, TA | TB | TN>;
50
+ /** Builds callable `$toggle` magic that returns independent toggle instances. */
51
+ declare function createToggleMagic(Alpine?: Pick<AlpineType.Alpine, "reactive">): ToggleMagic;
52
+ /** Alpine.js toggle plugin. Registers callable magic `$toggle`. */
53
+ declare function togglePlugin(Alpine: AlpineType.Alpine): void;
54
+
55
+ export { type ToggleBinaryStates, type ToggleInstance, type ToggleMagic, type ToggleOptions, type ToggleTernaryStates, type ToggleValue, createToggle, createToggleMagic, togglePlugin as default };
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ // src/index.ts
2
+ function isToggleState(states, value) {
3
+ return states.includes(value);
4
+ }
5
+ function indexOfState(states, value) {
6
+ return states.indexOf(value);
7
+ }
8
+ function buildToggle(options) {
9
+ const truly = options.states.truly;
10
+ const falsely = options.states.falsely;
11
+ const hasTernaryState = "ternary" in options.states;
12
+ const ternary = hasTernaryState ? options.states.ternary : void 0;
13
+ const stateValues = { truly, falsely, ternary };
14
+ const allStates = hasTernaryState ? [truly, falsely, ternary] : [truly, falsely];
15
+ const initial = "initial" in options ? options.initial : hasTernaryState ? ternary : truly;
16
+ const toggle = {
17
+ value: initial,
18
+ states: stateValues,
19
+ truly,
20
+ falsely,
21
+ ternary,
22
+ is(value) {
23
+ return this.value === value;
24
+ },
25
+ set(value) {
26
+ if (!isToggleState(allStates, value) || this.value === value) {
27
+ return false;
28
+ }
29
+ this.value = value;
30
+ return true;
31
+ },
32
+ toggle() {
33
+ if (hasTernaryState) {
34
+ if (this.value === ternary) {
35
+ this.value = truly;
36
+ } else if (this.value === truly) {
37
+ this.value = falsely;
38
+ } else {
39
+ this.value = truly;
40
+ }
41
+ } else {
42
+ this.value = this.value === truly ? falsely : truly;
43
+ }
44
+ return this.value;
45
+ },
46
+ cycle() {
47
+ const currentIndex = indexOfState(allStates, this.value);
48
+ const nextIndex = (currentIndex + 1) % allStates.length;
49
+ this.value = allStates[nextIndex];
50
+ return this.value;
51
+ },
52
+ reset() {
53
+ this.value = initial;
54
+ return this.value;
55
+ }
56
+ };
57
+ return toggle;
58
+ }
59
+ function createToggle(options) {
60
+ return buildToggle(options);
61
+ }
62
+ function createToggleMagic(Alpine) {
63
+ return ((options) => {
64
+ const instance = createToggle(
65
+ options
66
+ );
67
+ return Alpine ? Alpine.reactive(instance) : instance;
68
+ });
69
+ }
70
+ function togglePlugin(Alpine) {
71
+ Alpine.magic("toggle", () => createToggleMagic(Alpine));
72
+ }
73
+ export {
74
+ createToggle,
75
+ createToggleMagic,
76
+ togglePlugin as default
77
+ };
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type AlpineType from \"alpinejs\";\n\nexport interface ToggleBinaryStates<TA, TB> {\n truly: TA;\n falsely: TB;\n}\n\nexport interface ToggleTernaryStates<TA, TB, TN> extends ToggleBinaryStates<TA, TB> {\n ternary: TN;\n}\n\nexport type ToggleValue<TA, TB, TN = undefined> = TN extends undefined ? TA | TB : TA | TB | TN;\n\nexport interface ToggleOptions<TA, TB, TN = undefined> {\n states: ToggleBinaryStates<TA, TB> & { ternary?: TN };\n initial?: TA | TB | TN;\n}\n\nexport interface ToggleInstance<TA, TB, TN, V> {\n value: V;\n readonly states: ToggleBinaryStates<TA, TB> & { ternary: TN };\n readonly truly: TA;\n readonly falsely: TB;\n readonly ternary: TN;\n is(value: V): boolean;\n set(value: V): boolean;\n toggle(): V;\n cycle(): V;\n reset(): V;\n}\n\nexport type ToggleMagic = {\n <const TA, const TB>(options: {\n states: ToggleBinaryStates<TA, TB>;\n initial?: TA | TB;\n }): ToggleInstance<TA, TB, undefined, TA | TB>;\n <const TA, const TB, const TN>(options: {\n states: ToggleTernaryStates<TA, TB, TN>;\n initial?: TA | TB | TN;\n }): ToggleInstance<TA, TB, TN, TA | TB | TN>;\n};\n\nfunction isToggleState(states: readonly unknown[], value: unknown): boolean {\n return states.includes(value);\n}\n\nfunction indexOfState(states: readonly unknown[], value: unknown): number {\n return states.indexOf(value);\n}\n\nfunction buildToggle<TA, TB, TN>(options: ToggleOptions<TA, TB, TN> & { initial?: unknown }) {\n const truly = options.states.truly;\n const falsely = options.states.falsely;\n const hasTernaryState = \"ternary\" in options.states;\n const ternary = (hasTernaryState ? options.states.ternary : undefined) as TN;\n const stateValues = { truly, falsely, ternary };\n const allStates = hasTernaryState ? [truly, falsely, ternary] : [truly, falsely];\n const initial = (\n \"initial\" in options ? options.initial : hasTernaryState ? ternary : truly\n ) as unknown;\n\n const toggle = {\n value: initial,\n states: stateValues,\n truly,\n falsely,\n ternary,\n\n is(value: unknown) {\n return this.value === value;\n },\n\n set(value: unknown) {\n if (!isToggleState(allStates, value) || this.value === value) {\n return false;\n }\n\n this.value = value;\n return true;\n },\n\n toggle() {\n if (hasTernaryState) {\n if (this.value === ternary) {\n this.value = truly;\n } else if (this.value === truly) {\n this.value = falsely;\n } else {\n this.value = truly;\n }\n } else {\n this.value = this.value === truly ? falsely : truly;\n }\n\n return this.value;\n },\n\n cycle() {\n const currentIndex = indexOfState(allStates, this.value);\n const nextIndex = (currentIndex + 1) % allStates.length;\n this.value = allStates[nextIndex];\n return this.value;\n },\n\n reset() {\n this.value = initial;\n return this.value;\n },\n };\n\n return toggle;\n}\n\n/** Creates an independent toggle instance with optional ternary state. */\nexport function createToggle<const TA, const TB>(options: {\n states: ToggleBinaryStates<TA, TB>;\n initial?: TA | TB;\n}): ToggleInstance<TA, TB, undefined, TA | TB>;\nexport function createToggle<const TA, const TB, const TN>(options: {\n states: ToggleTernaryStates<TA, TB, TN>;\n initial?: TA | TB | TN;\n}): ToggleInstance<TA, TB, TN, TA | TB | TN>;\nexport function createToggle<const TA, const TB, const TN = undefined, const V = TA | TB>(\n options: ToggleOptions<TA, TB, TN> & { initial?: V }\n): ToggleInstance<TA, TB, TN, V> {\n return buildToggle(options) as unknown as ToggleInstance<TA, TB, TN, V>;\n}\n\n/** Builds callable `$toggle` magic that returns independent toggle instances. */\nexport function createToggleMagic(Alpine?: Pick<AlpineType.Alpine, \"reactive\">): ToggleMagic {\n return ((options: Parameters<ToggleMagic>[0]) => {\n const instance = createToggle(\n options as ToggleOptions<unknown, unknown, unknown> & { initial?: unknown }\n );\n return Alpine ? Alpine.reactive(instance) : instance;\n }) as ToggleMagic;\n}\n\n/** Alpine.js toggle plugin. Registers callable magic `$toggle`. */\nexport default function togglePlugin(Alpine: AlpineType.Alpine): void {\n Alpine.magic(\"toggle\", () => createToggleMagic(Alpine));\n}\n"],"mappings":";AA0CA,SAAS,cAAc,QAA4B,OAAyB;AAC1E,SAAO,OAAO,SAAS,KAAK;AAC9B;AAEA,SAAS,aAAa,QAA4B,OAAwB;AACxE,SAAO,OAAO,QAAQ,KAAK;AAC7B;AAEA,SAAS,YAAwB,SAA4D;AAC3F,QAAM,QAAQ,QAAQ,OAAO;AAC7B,QAAM,UAAU,QAAQ,OAAO;AAC/B,QAAM,kBAAkB,aAAa,QAAQ;AAC7C,QAAM,UAAW,kBAAkB,QAAQ,OAAO,UAAU;AAC5D,QAAM,cAAc,EAAE,OAAO,SAAS,QAAQ;AAC9C,QAAM,YAAY,kBAAkB,CAAC,OAAO,SAAS,OAAO,IAAI,CAAC,OAAO,OAAO;AAC/E,QAAM,UACJ,aAAa,UAAU,QAAQ,UAAU,kBAAkB,UAAU;AAGvE,QAAM,SAAS;AAAA,IACb,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IAEA,GAAG,OAAgB;AACjB,aAAO,KAAK,UAAU;AAAA,IACxB;AAAA,IAEA,IAAI,OAAgB;AAClB,UAAI,CAAC,cAAc,WAAW,KAAK,KAAK,KAAK,UAAU,OAAO;AAC5D,eAAO;AAAA,MACT;AAEA,WAAK,QAAQ;AACb,aAAO;AAAA,IACT;AAAA,IAEA,SAAS;AACP,UAAI,iBAAiB;AACnB,YAAI,KAAK,UAAU,SAAS;AAC1B,eAAK,QAAQ;AAAA,QACf,WAAW,KAAK,UAAU,OAAO;AAC/B,eAAK,QAAQ;AAAA,QACf,OAAO;AACL,eAAK,QAAQ;AAAA,QACf;AAAA,MACF,OAAO;AACL,aAAK,QAAQ,KAAK,UAAU,QAAQ,UAAU;AAAA,MAChD;AAEA,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,QAAQ;AACN,YAAM,eAAe,aAAa,WAAW,KAAK,KAAK;AACvD,YAAM,aAAa,eAAe,KAAK,UAAU;AACjD,WAAK,QAAQ,UAAU,SAAS;AAChC,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,QAAQ;AACN,WAAK,QAAQ;AACb,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,aACd,SAC+B;AAC/B,SAAO,YAAY,OAAO;AAC5B;AAGO,SAAS,kBAAkB,QAA2D;AAC3F,UAAQ,CAAC,YAAwC;AAC/C,UAAM,WAAW;AAAA,MACf;AAAA,IACF;AACA,WAAO,SAAS,OAAO,SAAS,QAAQ,IAAI;AAAA,EAC9C;AACF;AAGe,SAAR,aAA8B,QAAiC;AACpE,SAAO,MAAM,UAAU,MAAM,kBAAkB,MAAM,CAAC;AACxD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ailuracode/alpine-toggle",
3
+ "version": "0.1.0",
4
+ "description": "Alpine.js toggle magic with binary and ternary state inference",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "ailuracode",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/ailuracode/alpine.git",
14
+ "directory": "packages/toggle"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/ailuracode/alpine/issues"
18
+ },
19
+ "homepage": "https://github.com/ailuracode/alpine/tree/master/packages/toggle#readme",
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./global": {
30
+ "types": "./dist/global.d.ts"
31
+ }
32
+ },
33
+ "types": "./dist/global.d.ts",
34
+ "peerDependencies": {
35
+ "alpinejs": "^3.0.0",
36
+ "@types/alpinejs": "^3.13.11"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "@types/alpinejs": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "keywords": [
44
+ "alpinejs",
45
+ "alpine",
46
+ "plugin",
47
+ "toggle",
48
+ "state"
49
+ ],
50
+ "scripts": {
51
+ "build": "tsup src/index.ts --format esm --dts --clean --sourcemap --out-dir dist && cp src/global.d.ts dist/global.d.ts",
52
+ "test": "vitest run --config ../../vitest.config.ts test"
53
+ }
54
+ }