nitro_kit 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8300c577f175e7d5d72554924f11f38dc66ca00b4dee13d0ec68aa5a3e1d0cf
4
- data.tar.gz: ea1bf5a4b4d259a41c5979dd1f380631deb658ab68feb98d83afc978a340fe58
3
+ metadata.gz: c6eec3cce7aa4fea915dc5db94356849f55d1335797a682651382287d9f63207
4
+ data.tar.gz: ea81efcdcd9d8b6e60a697f7d3b6e38ed26e6f6226f48a6ad249f9b984c6ae1b
5
5
  SHA512:
6
- metadata.gz: 0a1f06668d4e2aae4ad2863bcb3c5925d96ca62567e7bc0a3c7bddc6f2dcd36131bcc6c3c6834b4a30f88dbe5c22e695261a1047cd2d50169846bdc944496df5
7
- data.tar.gz: 3ecb781fcbf9e5c8dd270c68d07dfc54517ecb32ba6096b65a91d497562edda9f2dfa99255deb75e99262971272f1198108e6cf214cabb65ce0b1048f4853abc
6
+ metadata.gz: 48a1d7b809cad9a30dae1e0d53210faea9c13e22b5c977fab4c3f4024a3fd7f7a4a30e50e69a449e817083a586388d162fc43d7ddf6a96a1159472b26eab0259
7
+ data.tar.gz: faecf1f62cd5e31fb729dd0c6ed80ff75245661d57adf09930e9b5a8de0b7f75f622776a391d6d8ebf22233a2a17375df02eb1bf459fdb0e47c6d0dc086f0c1f
@@ -0,0 +1,18 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["trigger", "content"];
5
+
6
+ toggle(event) {
7
+ const trigger = event.target;
8
+ const content = trigger.parentElement.querySelector(
9
+ "[data-nk--accordion-target=content]",
10
+ );
11
+
12
+ const isExpanded = trigger.getAttribute("aria-expanded") === "true";
13
+
14
+ // Toggle current item
15
+ trigger.setAttribute("aria-expanded", (!isExpanded).toString());
16
+ content.setAttribute("aria-hidden", isExpanded.toString());
17
+ }
18
+ }
@@ -0,0 +1,130 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import Combobox from "@github/combobox-nav";
3
+ import {
4
+ computePosition,
5
+ offset,
6
+ flip,
7
+ shift,
8
+ autoUpdate,
9
+ } from "@floating-ui/dom";
10
+
11
+ export default class extends Controller {
12
+ static targets = ["input", "list", "hiddenField", "clearButton"];
13
+ static values = {
14
+ open: { type: Boolean, default: false },
15
+ // Options for floating-ui
16
+ placement: { type: String },
17
+ // Options for combobox-nav
18
+ tabInsertsSuggestions: { type: Boolean },
19
+ firstOptionSelectionMode: { type: String },
20
+ scrollIntoViewOptions: { type: Object },
21
+ };
22
+
23
+ connect() {
24
+ this.combobox = new Combobox(this.inputTarget, this.listTarget, {
25
+ tabInsertsSuggestions: this.tabInsertsSuggestionsValue,
26
+ firstOptionSelectionMode: this.firstOptionSelectionModeValue,
27
+ scrollIntoViewOptions: this.scrollIntoViewOptionsValue,
28
+ });
29
+
30
+ this.updatePosition();
31
+
32
+ this.listTarget.addEventListener("combobox-commit", (event) => {
33
+ this.select(event);
34
+ this.close();
35
+ });
36
+ }
37
+
38
+ disconnect() {
39
+ this.combobox.destroy();
40
+ }
41
+
42
+ select(event) {
43
+ this.inputTarget.value = event.target.textContent;
44
+ this.hiddenFieldTarget.value =
45
+ event.target.dataset.value || event.target.textContent;
46
+ }
47
+
48
+ open() {
49
+ this.openValue = true;
50
+ }
51
+
52
+ close() {
53
+ this.openValue = false;
54
+ }
55
+
56
+ focusShift({ target }) {
57
+ if (!this.openValue) return;
58
+ if (this.element.contains(target)) return;
59
+
60
+ this.close();
61
+ }
62
+
63
+ windowClick({ target }) {
64
+ if (!this.openValue) return;
65
+ if (this.element.contains(target)) return;
66
+
67
+ this.close();
68
+ }
69
+
70
+ clear() {
71
+ this.combobox.resetSelection();
72
+ this.inputTarget.value = "";
73
+ this.input();
74
+ this.hiddenFieldTarget.value = "";
75
+ }
76
+
77
+ input(_event) {
78
+ if (!this.isOpen) this.open();
79
+
80
+ const filter = this.inputTarget.value.toLowerCase();
81
+
82
+ Array.from(this.listTarget.children).forEach((item) => {
83
+ const value = item.dataset.value?.toLowerCase();
84
+ const text = item.textContent.toLowerCase();
85
+
86
+ if (value?.includes(filter) || text.includes(filter)) {
87
+ item.setAttribute("role", "option");
88
+ } else {
89
+ item.removeAttribute("role");
90
+ }
91
+ });
92
+
93
+ this.hiddenFieldTarget.value = this.inputTarget.value;
94
+ }
95
+
96
+ openValueChanged(state, _previous) {
97
+ if (!this.combobox) return;
98
+
99
+ if (state) {
100
+ this.combobox.start();
101
+
102
+ this.listTarget.dataset.state = "open";
103
+
104
+ this.clearAutoUpdate = autoUpdate(
105
+ this.inputTarget,
106
+ this.listTarget,
107
+ this.updatePosition,
108
+ );
109
+ } else {
110
+ this.combobox.stop();
111
+
112
+ this.listTarget.dataset.state = "closed";
113
+
114
+ if (this.clearAutoUpdate) {
115
+ this.clearAutoUpdate();
116
+ }
117
+ }
118
+ }
119
+
120
+ updatePosition = () => {
121
+ computePosition(this.inputTarget, this.listTarget, {
122
+ placement: this.placementValue,
123
+ middleware: [offset(5), flip(), shift({ padding: 5 })],
124
+ }).then(({ x, y }) => {
125
+ this.listTarget.style.left = `${x}px`;
126
+ this.listTarget.style.top = `${y}px`;
127
+ this.listTarget.style.width = `${this.inputTarget.clientWidth}px`;
128
+ });
129
+ };
130
+ }
@@ -0,0 +1,5 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["input"];
5
+ }
@@ -0,0 +1,19 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["trigger", "dialog"];
5
+
6
+ open() {
7
+ this.dialogTarget.showModal();
8
+ }
9
+
10
+ close() {
11
+ this.dialogTarget.close();
12
+ }
13
+
14
+ clickOutside(event) {
15
+ if (event.target === this.dialogTarget) {
16
+ this.close();
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,78 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import {
3
+ computePosition,
4
+ offset,
5
+ flip,
6
+ shift,
7
+ autoUpdate,
8
+ } from "@floating-ui/dom";
9
+
10
+ export default class extends Controller {
11
+ static targets = ["trigger", "content"];
12
+ static values = {
13
+ placement: { type: String, default: "bottom" },
14
+ };
15
+
16
+ connect() {
17
+ this.updatePosition();
18
+ }
19
+
20
+ disconnect() {
21
+ this.close();
22
+ }
23
+
24
+ get isExpanded() {
25
+ return this.triggerTarget.getAttribute("aria-expanded") === "true";
26
+ }
27
+
28
+ updatePosition = () => {
29
+ computePosition(this.triggerTarget, this.contentTarget, {
30
+ placement: this.placementValue,
31
+ middleware: [offset(5), flip(), shift({ padding: 5 })],
32
+ }).then(({ x, y }) => {
33
+ this.contentTarget.style.left = `${x}px`;
34
+ this.contentTarget.style.top = `${y}px`;
35
+ });
36
+ };
37
+
38
+ open = () => {
39
+ this.triggerTarget.setAttribute("aria-expanded", "true");
40
+ this.contentTarget.setAttribute("aria-hidden", "false");
41
+
42
+ document.addEventListener("click", this.clickOutside);
43
+
44
+ this.clearAutoUpdate = autoUpdate(
45
+ this.triggerTarget,
46
+ this.contentTarget,
47
+ this.updatePosition,
48
+ );
49
+ };
50
+
51
+ close = () => {
52
+ this.triggerTarget.setAttribute("aria-expanded", "false");
53
+ this.contentTarget.setAttribute("aria-hidden", "true");
54
+
55
+ document.removeEventListener("click", this.clickOutside);
56
+
57
+ if (this.clearAutoUpdate) {
58
+ this.clearAutoUpdate();
59
+ }
60
+ };
61
+
62
+ toggle = () => {
63
+ if (this.isExpanded) {
64
+ this.close();
65
+ } else {
66
+ this.open();
67
+ }
68
+ };
69
+
70
+ clickOutside = (event) => {
71
+ if (
72
+ !this.contentTarget.contains(event.target) &&
73
+ !this.triggerTarget.contains(event.target)
74
+ ) {
75
+ this.close();
76
+ }
77
+ };
78
+ }
@@ -0,0 +1,32 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ if (!this.element.hasAttribute("tabindex")) {
6
+ this.element.setAttribute("tabindex", "0");
7
+ }
8
+ }
9
+
10
+ click() {
11
+ if (this.element.hasAttribute("disabled")) return;
12
+
13
+ this.toggle();
14
+ }
15
+
16
+ keydown(event) {
17
+ if (this.element.hasAttribute("disabled")) return;
18
+
19
+ if (event.code === "Space" || event.code === "Enter") {
20
+ event.preventDefault();
21
+ this.toggle();
22
+ }
23
+ }
24
+
25
+ get checked() {
26
+ return this.element.getAttribute("aria-checked") === "true";
27
+ }
28
+
29
+ toggle() {
30
+ this.element.setAttribute("aria-checked", (!this.checked).toString());
31
+ }
32
+ }
@@ -0,0 +1,46 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["tab", "panel"];
5
+ static values = { active: String };
6
+
7
+ setActiveTab(event) {
8
+ this.activeValue = event.params.key;
9
+ }
10
+
11
+ prevTab(event) {
12
+ const prevTab = event.target.previousElementSibling;
13
+ if (prevTab) {
14
+ prevTab.click();
15
+ prevTab.focus();
16
+ }
17
+ }
18
+
19
+ nextTab(event) {
20
+ const nextTab = event.target.nextElementSibling;
21
+ if (nextTab) {
22
+ nextTab.click();
23
+ nextTab.focus();
24
+ }
25
+ }
26
+
27
+ activeValueChanged() {
28
+ const value = this.activeValue;
29
+
30
+ this.panelTargets.forEach((panel) => {
31
+ if (panel.dataset.key === value) {
32
+ panel.ariaHidden = false;
33
+ } else {
34
+ panel.ariaHidden = true;
35
+ }
36
+ });
37
+
38
+ this.tabTargets.forEach((tab) => {
39
+ if (tab.dataset.key === value) {
40
+ tab.ariaSelected = true;
41
+ } else {
42
+ tab.ariaSelected = false;
43
+ }
44
+ });
45
+ }
46
+ }
@@ -0,0 +1,68 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["list", "template", "sink"];
5
+ static values = {
6
+ duration: { type: Number, default: 5000 },
7
+ };
8
+
9
+ connect() {
10
+ this.#flushSink();
11
+
12
+ if (this.hasSinkTarget) {
13
+ this.mutationObserver = new MutationObserver(([event]) => {
14
+ if (event.addedNodes.length === 0) return;
15
+ this.#flushSink();
16
+ });
17
+ this.mutationObserver.observe(this.sinkTarget, { childList: true });
18
+ }
19
+ }
20
+
21
+ disconnect() {
22
+ if (this.mutationObserver) this.mutationObserver.disconnect();
23
+ }
24
+
25
+ toast({ params }) {
26
+ const { title, description } = params;
27
+ const item = this.templateTarget.content.cloneNode(true);
28
+
29
+ item.querySelector("[data-slot=title]").textContent = title;
30
+ item.querySelector("[data-slot=description]").textContent = description;
31
+
32
+ this.show(item);
33
+ }
34
+
35
+ show(item) {
36
+ this.clear();
37
+ this.listTarget.appendChild(item);
38
+
39
+ requestAnimationFrame(() => {
40
+ this.listTarget.children[0].dataset.state = "open";
41
+ });
42
+
43
+ if (this.timer) clearTimeout(this.timer);
44
+
45
+ this.timer = setTimeout(() => {
46
+ this.hide();
47
+ }, this.durationValue);
48
+ }
49
+
50
+ hide() {
51
+ this.listTarget.children[0].dataset.state = "closed";
52
+
53
+ setTimeout(() => {
54
+ this.clear();
55
+ }, 250);
56
+ }
57
+
58
+ clear() {
59
+ this.listTarget.innerHTML = "";
60
+ }
61
+
62
+ #flushSink() {
63
+ for (const li of this.sinkTarget.children) {
64
+ this.show(li.cloneNode(true));
65
+ li.remove();
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,59 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import {
3
+ computePosition,
4
+ offset,
5
+ flip,
6
+ shift,
7
+ autoUpdate,
8
+ } from "@floating-ui/dom";
9
+
10
+ export default class extends Controller {
11
+ static targets = ["content"];
12
+ static values = {
13
+ open: { type: Boolean, default: false },
14
+ // Options for floating-ui
15
+ placement: { type: String, default: "top" },
16
+ };
17
+
18
+ connect() {
19
+ this.updatePosition();
20
+ }
21
+
22
+ disconnect() {
23
+ this.close();
24
+ }
25
+
26
+ open() {
27
+ this.openValue = true;
28
+ }
29
+
30
+ close() {
31
+ this.openValue = false;
32
+ }
33
+
34
+ openValueChanged(state, _previous) {
35
+ this.contentTarget.dataset.state = state ? "open" : "closed";
36
+
37
+ if (state) {
38
+ this.clearAutoUpdate = autoUpdate(
39
+ this.element,
40
+ this.contentTarget,
41
+ this.updatePosition,
42
+ );
43
+ } else {
44
+ if (this.clearAutoUpdate) {
45
+ this.clearAutoUpdate();
46
+ }
47
+ }
48
+ }
49
+
50
+ updatePosition = () => {
51
+ computePosition(this.element, this.contentTarget, {
52
+ placement: this.placementValue,
53
+ middleware: [offset(5), flip(), shift({ padding: 5 })],
54
+ }).then(({ x, y }) => {
55
+ this.contentTarget.style.left = `${x}px`;
56
+ this.contentTarget.style.top = `${y}px`;
57
+ });
58
+ };
59
+ }
@@ -1,3 +1,3 @@
1
1
  module NitroKit
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nitro_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikkel Malmberg
@@ -120,6 +120,15 @@ files:
120
120
  - app/helpers/nitro_kit/textarea_helper.rb
121
121
  - app/helpers/nitro_kit/toast_helper.rb
122
122
  - app/helpers/nitro_kit/tooltip_helper.rb
123
+ - app/javascript/controllers/nk/accordion_controller.js
124
+ - app/javascript/controllers/nk/combobox_controller.js
125
+ - app/javascript/controllers/nk/datepicker_controller.js
126
+ - app/javascript/controllers/nk/dialog_controller.js
127
+ - app/javascript/controllers/nk/dropdown_controller.js
128
+ - app/javascript/controllers/nk/switch_controller.js
129
+ - app/javascript/controllers/nk/tabs_controller.js
130
+ - app/javascript/controllers/nk/toast_controller.js
131
+ - app/javascript/controllers/nk/tooltip_controller.js
123
132
  - lib/generators/nitro_kit/component_generator.rb
124
133
  - lib/nitro_kit.rb
125
134
  - lib/nitro_kit/engine.rb