kiso 0.4.3.pre → 0.5.0.pre
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.
- checksums.yaml +4 -4
- data/app/assets/tailwind/kiso/button.css +10 -0
- data/app/assets/tailwind/kiso/engine.css +2 -0
- data/app/assets/tailwind/kiso/tooltip.css +48 -0
- data/app/javascript/controllers/kiso/dialog_trigger_controller.js +80 -0
- data/app/javascript/controllers/kiso/index.d.ts +11 -0
- data/app/javascript/controllers/kiso/index.js +9 -0
- data/app/javascript/controllers/kiso/tooltip_controller.js +212 -0
- data/app/javascript/kiso/utils/positioning.js +34 -3
- data/app/views/kiso/components/_avatar.html.erb +5 -2
- data/app/views/kiso/components/_spinner.html.erb +7 -0
- data/app/views/kiso/components/_tooltip.html.erb +25 -0
- data/app/views/kiso/components/tooltip/_content.html.erb +14 -0
- data/app/views/kiso/components/tooltip/_trigger.html.erb +9 -0
- data/config/locales/en.yml +4 -0
- data/lib/kiso/configuration.rb +2 -1
- data/lib/kiso/presets/rounded.rb +4 -1
- data/lib/kiso/presets/sharp.rb +4 -1
- data/lib/kiso/themes/avatar.rb +5 -0
- data/lib/kiso/themes/button.rb +1 -1
- data/lib/kiso/themes/spinner.rb +16 -0
- data/lib/kiso/themes/tooltip.rb +26 -0
- data/lib/kiso/version.rb +1 -1
- data/lib/kiso.rb +2 -0
- metadata +12 -3
- data/CHANGELOG.md +0 -138
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4bf4475ba64978e58e6321ac224b3912cf463dae75462ee3372f86faf4b69799
|
|
4
|
+
data.tar.gz: ee8c23fdd9a81b0b4abd8a097371a4720b8327e2c719c6b1a5cb84ea21a22962
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: abdb896617cba586d6906624bb2e30434ad40ccd2c1a12d589284ca43149056724c4ecb6dad7cb4a27915f3dad846e64b2a12bc3efa5a0d0fe82378aaf6494ad
|
|
7
|
+
data.tar.gz: 00d0ce8bd9933e5f3500d3ac0dfa57a068ae8c3923371943e398122f179e508fe5c7bd39b308df15a92eda836e50a41693be5e295e5a7c1bd3f6aea1bf2a57af
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* Default display for buttons — lives in @layer components so utility classes
|
|
2
|
+
(including `hidden`) override via the higher-priority utilities layer. When
|
|
3
|
+
a utility like `hidden` is removed via JS, this rule restores inline-flex.
|
|
4
|
+
Fixes: https://github.com/steveclarke/kiso/issues/200 */
|
|
5
|
+
|
|
6
|
+
@layer components {
|
|
7
|
+
[data-slot="button"] {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
that are awkward to express in ERB. Most styling lives in Ruby theme modules
|
|
4
4
|
(lib/kiso/themes/) as computed Tailwind classes. */
|
|
5
5
|
|
|
6
|
+
@import "./button.css";
|
|
6
7
|
@import "./checkbox.css";
|
|
7
8
|
@import "./radio-group.css";
|
|
8
9
|
@import "./color-mode.css";
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
@import "./dialog.css";
|
|
11
12
|
@import "./input-otp.css";
|
|
12
13
|
@import "./slider.css";
|
|
14
|
+
@import "./tooltip.css";
|
|
13
15
|
|
|
14
16
|
/* Scan Kiso's own files so host apps don't need to know the gem's internals.
|
|
15
17
|
Paths are relative to THIS file (app/assets/tailwind/kiso/engine.css).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* Tooltip entry/exit animations and arrow positioning. */
|
|
2
|
+
|
|
3
|
+
/* Tooltip root — inline-flex via @layer components so utilities can override */
|
|
4
|
+
@layer components {
|
|
5
|
+
[data-slot="tooltip"] {
|
|
6
|
+
display: inline-flex;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* The browser UA stylesheet hides [popover]:not(:popover-open) with
|
|
11
|
+
display: none, but Tailwind's `flex` utility (author layer) overrides it.
|
|
12
|
+
Explicitly enforce hidden state for non-open popovers. */
|
|
13
|
+
[data-slot="tooltip-content"]:not(:popover-open) {
|
|
14
|
+
display: none;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Reset UA popover styles — browsers apply inset: 0, margin: auto, and
|
|
18
|
+
width/height: fit-content to [popover]:popover-open, which overrides
|
|
19
|
+
Floating UI's inline-style positioning. */
|
|
20
|
+
[data-slot="tooltip-content"] {
|
|
21
|
+
inset: unset;
|
|
22
|
+
margin: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Entry animation — fade + scale from 95% */
|
|
26
|
+
[data-slot="tooltip-content"][data-state="open"] {
|
|
27
|
+
animation: kiso-tooltip-in 150ms ease-out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Exit animation — fade out + scale to 95% */
|
|
31
|
+
[data-slot="tooltip-content"][data-state="closed"] {
|
|
32
|
+
animation: kiso-tooltip-out 100ms ease-in forwards;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@keyframes kiso-tooltip-in {
|
|
36
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
37
|
+
}
|
|
38
|
+
@keyframes kiso-tooltip-out {
|
|
39
|
+
to { opacity: 0; transform: scale(0.95); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Respect reduced motion */
|
|
43
|
+
@media (prefers-reduced-motion: reduce) {
|
|
44
|
+
[data-slot="tooltip-content"][data-state="open"],
|
|
45
|
+
[data-slot="tooltip-content"][data-state="closed"] {
|
|
46
|
+
animation: none;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Opens or closes a dialog from anywhere on the page by ID.
|
|
5
|
+
*
|
|
6
|
+
* Use when the trigger button lives outside the dialog's DOM scope
|
|
7
|
+
* (e.g., a toolbar button opening a confirmation dialog rendered
|
|
8
|
+
* elsewhere on the page).
|
|
9
|
+
*
|
|
10
|
+
* Works with both `kui(:dialog)` and `kui(:alert_dialog)` since
|
|
11
|
+
* both use the `kiso--dialog` Stimulus controller internally.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <!-- Dialog rendered anywhere -->
|
|
15
|
+
* <dialog id="invite-dialog" data-controller="kiso--dialog" ...>
|
|
16
|
+
* ...
|
|
17
|
+
* </dialog>
|
|
18
|
+
*
|
|
19
|
+
* <!-- Trigger from a toolbar, sidebar, or any other scope -->
|
|
20
|
+
* <button data-controller="kiso--dialog-trigger"
|
|
21
|
+
* data-kiso--dialog-trigger-dialog-id-value="invite-dialog"
|
|
22
|
+
* data-action="kiso--dialog-trigger#open">
|
|
23
|
+
* Invite
|
|
24
|
+
* </button>
|
|
25
|
+
*
|
|
26
|
+
* @property {string} dialogIdValue - The DOM id of the target dialog element
|
|
27
|
+
*
|
|
28
|
+
* @fires kiso--dialog:open - Forwarded from the target dialog controller
|
|
29
|
+
* @fires kiso--dialog:close - Forwarded from the target dialog controller
|
|
30
|
+
*/
|
|
31
|
+
export default class extends Controller {
|
|
32
|
+
static values = {
|
|
33
|
+
dialogId: String,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Opens the target dialog.
|
|
38
|
+
*/
|
|
39
|
+
open() {
|
|
40
|
+
this._withDialogController((controller) => controller.open())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Closes the target dialog.
|
|
45
|
+
*/
|
|
46
|
+
close() {
|
|
47
|
+
this._withDialogController((controller) => controller.close())
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Toggles the target dialog open or closed.
|
|
52
|
+
*/
|
|
53
|
+
toggle() {
|
|
54
|
+
this._withDialogController((controller) => {
|
|
55
|
+
if (controller.element.open) {
|
|
56
|
+
controller.close()
|
|
57
|
+
} else {
|
|
58
|
+
controller.open()
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Finds the dialog element and its Stimulus controller, then
|
|
65
|
+
* calls the provided callback with the controller instance.
|
|
66
|
+
*
|
|
67
|
+
* @param {function} callback - Receives the dialog controller
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
_withDialogController(callback) {
|
|
71
|
+
const dialog = document.getElementById(this.dialogIdValue)
|
|
72
|
+
if (!dialog) return
|
|
73
|
+
|
|
74
|
+
const controller = this.application.getControllerForElementAndIdentifier(dialog, "kiso--dialog")
|
|
75
|
+
|
|
76
|
+
if (controller) {
|
|
77
|
+
callback(controller)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -5,8 +5,19 @@ declare const KisoUi: {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export default KisoUi
|
|
8
|
+
export const KisoAlertController: typeof Controller
|
|
8
9
|
export const KisoComboboxController: typeof Controller
|
|
10
|
+
export const KisoCommandController: typeof Controller
|
|
11
|
+
export const KisoCommandDialogController: typeof Controller
|
|
12
|
+
export const KisoDialogController: typeof Controller
|
|
13
|
+
export const KisoDialogTriggerController: typeof Controller
|
|
9
14
|
export const KisoDropdownMenuController: typeof Controller
|
|
15
|
+
export const KisoInputOtpController: typeof Controller
|
|
16
|
+
export const KisoPopoverController: typeof Controller
|
|
10
17
|
export const KisoSelectController: typeof Controller
|
|
18
|
+
export const KisoSidebarController: typeof Controller
|
|
19
|
+
export const KisoSliderController: typeof Controller
|
|
20
|
+
export const KisoThemeController: typeof Controller
|
|
11
21
|
export const KisoToggleController: typeof Controller
|
|
12
22
|
export const KisoToggleGroupController: typeof Controller
|
|
23
|
+
export const KisoTooltipController: typeof Controller
|
|
@@ -3,14 +3,17 @@ import KisoComboboxController from "./combobox_controller.js"
|
|
|
3
3
|
import KisoCommandController from "./command_controller.js"
|
|
4
4
|
import KisoCommandDialogController from "./command_dialog_controller.js"
|
|
5
5
|
import KisoDialogController from "./dialog_controller.js"
|
|
6
|
+
import KisoDialogTriggerController from "./dialog_trigger_controller.js"
|
|
6
7
|
import KisoDropdownMenuController from "./dropdown_menu_controller.js"
|
|
7
8
|
import KisoInputOtpController from "./input_otp_controller.js"
|
|
8
9
|
import KisoPopoverController from "./popover_controller.js"
|
|
9
10
|
import KisoSelectController from "./select_controller.js"
|
|
10
11
|
import KisoSidebarController from "./sidebar_controller.js"
|
|
12
|
+
import KisoSliderController from "./slider_controller.js"
|
|
11
13
|
import KisoThemeController from "./theme_controller.js"
|
|
12
14
|
import KisoToggleController from "./toggle_controller.js"
|
|
13
15
|
import KisoToggleGroupController from "./toggle_group_controller.js"
|
|
16
|
+
import KisoTooltipController from "./tooltip_controller.js"
|
|
14
17
|
|
|
15
18
|
const KisoUi = {
|
|
16
19
|
start(application) {
|
|
@@ -19,14 +22,17 @@ const KisoUi = {
|
|
|
19
22
|
application.register("kiso--command", KisoCommandController)
|
|
20
23
|
application.register("kiso--command-dialog", KisoCommandDialogController)
|
|
21
24
|
application.register("kiso--dialog", KisoDialogController)
|
|
25
|
+
application.register("kiso--dialog-trigger", KisoDialogTriggerController)
|
|
22
26
|
application.register("kiso--dropdown-menu", KisoDropdownMenuController)
|
|
23
27
|
application.register("kiso--input-otp", KisoInputOtpController)
|
|
24
28
|
application.register("kiso--popover", KisoPopoverController)
|
|
25
29
|
application.register("kiso--select", KisoSelectController)
|
|
26
30
|
application.register("kiso--sidebar", KisoSidebarController)
|
|
31
|
+
application.register("kiso--slider", KisoSliderController)
|
|
27
32
|
application.register("kiso--theme", KisoThemeController)
|
|
28
33
|
application.register("kiso--toggle", KisoToggleController)
|
|
29
34
|
application.register("kiso--toggle-group", KisoToggleGroupController)
|
|
35
|
+
application.register("kiso--tooltip", KisoTooltipController)
|
|
30
36
|
},
|
|
31
37
|
}
|
|
32
38
|
|
|
@@ -37,12 +43,15 @@ export {
|
|
|
37
43
|
KisoCommandController,
|
|
38
44
|
KisoCommandDialogController,
|
|
39
45
|
KisoDialogController,
|
|
46
|
+
KisoDialogTriggerController,
|
|
40
47
|
KisoDropdownMenuController,
|
|
41
48
|
KisoInputOtpController,
|
|
42
49
|
KisoPopoverController,
|
|
43
50
|
KisoSelectController,
|
|
44
51
|
KisoSidebarController,
|
|
52
|
+
KisoSliderController,
|
|
45
53
|
KisoThemeController,
|
|
46
54
|
KisoToggleController,
|
|
47
55
|
KisoToggleGroupController,
|
|
56
|
+
KisoTooltipController,
|
|
48
57
|
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import { startPositioning } from "kiso-ui/utils/positioning"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tooltip controller — shows a floating tooltip on hover or keyboard focus.
|
|
6
|
+
* Uses Floating UI for positioning and the native `[popover]` attribute for
|
|
7
|
+
* top-layer rendering (no z-index issues).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <div data-controller="kiso--tooltip"
|
|
11
|
+
* data-kiso--tooltip-side-value="top"
|
|
12
|
+
* data-kiso--tooltip-align-value="center"
|
|
13
|
+
* data-kiso--tooltip-delay-value="0"
|
|
14
|
+
* data-slot="tooltip">
|
|
15
|
+
* <div data-kiso--tooltip-target="trigger"
|
|
16
|
+
* data-action="mouseenter->kiso--tooltip#show mouseleave->kiso--tooltip#hide
|
|
17
|
+
* focusin->kiso--tooltip#show focusout->kiso--tooltip#hide"
|
|
18
|
+
* data-slot="tooltip-trigger">
|
|
19
|
+
* <button type="button">Hover me</button>
|
|
20
|
+
* </div>
|
|
21
|
+
* <div data-kiso--tooltip-target="content"
|
|
22
|
+
* data-slot="tooltip-content"
|
|
23
|
+
* popover="manual"
|
|
24
|
+
* role="tooltip">
|
|
25
|
+
* Tooltip text
|
|
26
|
+
* <div data-kiso--tooltip-target="arrow" data-slot="tooltip-arrow"></div>
|
|
27
|
+
* </div>
|
|
28
|
+
* </div>
|
|
29
|
+
*
|
|
30
|
+
* @property {HTMLElement} triggerTarget - Element that activates the tooltip on hover/focus
|
|
31
|
+
* @property {HTMLElement} contentTarget - The floating tooltip panel (popover)
|
|
32
|
+
* @property {HTMLElement} arrowTarget - Arrow element positioned by Floating UI
|
|
33
|
+
*
|
|
34
|
+
* @fires kiso--tooltip:show - When the tooltip becomes visible
|
|
35
|
+
* @fires kiso--tooltip:hide - When the tooltip is hidden
|
|
36
|
+
*/
|
|
37
|
+
export default class extends Controller {
|
|
38
|
+
static targets = ["trigger", "content", "arrow"]
|
|
39
|
+
static values = {
|
|
40
|
+
side: { type: String, default: "top" },
|
|
41
|
+
align: { type: String, default: "center" },
|
|
42
|
+
delay: { type: Number, default: 0 },
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
connect() {
|
|
46
|
+
this._open = false
|
|
47
|
+
|
|
48
|
+
// Link trigger to tooltip content via aria-describedby
|
|
49
|
+
this._triggerEl =
|
|
50
|
+
this.triggerTarget.querySelector("button, a, [tabindex]") || this.triggerTarget
|
|
51
|
+
this._tooltipId = this.contentTarget.id || `tooltip-${crypto.randomUUID().slice(0, 8)}`
|
|
52
|
+
this.contentTarget.id = this._tooltipId
|
|
53
|
+
this._triggerEl.setAttribute("aria-describedby", this._tooltipId)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
disconnect() {
|
|
57
|
+
this._cleanupPosition?.()
|
|
58
|
+
this._clearTimers()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Shows the tooltip after the configured delay.
|
|
63
|
+
* Called on mouseenter and focusin on the trigger.
|
|
64
|
+
*/
|
|
65
|
+
show() {
|
|
66
|
+
this._clearHideTimeout()
|
|
67
|
+
|
|
68
|
+
if (this._open) return
|
|
69
|
+
|
|
70
|
+
const delay = this.delayValue
|
|
71
|
+
if (delay > 0) {
|
|
72
|
+
this._showTimeout = setTimeout(() => this._doShow(), delay)
|
|
73
|
+
} else {
|
|
74
|
+
this._doShow()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Hides the tooltip with a small delay to allow the mouse to cross
|
|
80
|
+
* the gap between trigger and tooltip content.
|
|
81
|
+
* Called on mouseleave and focusout on the trigger.
|
|
82
|
+
*/
|
|
83
|
+
hide() {
|
|
84
|
+
this._clearShowTimeout()
|
|
85
|
+
|
|
86
|
+
if (!this._open) return
|
|
87
|
+
|
|
88
|
+
// Small delay lets the mouse cross the offset gap to the content
|
|
89
|
+
this._hideTimeout = setTimeout(() => this._doHide(), 100)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Cancels a pending hide when the mouse enters the tooltip content.
|
|
94
|
+
* Keeps the tooltip visible while the user reads it.
|
|
95
|
+
*/
|
|
96
|
+
contentMouseEnter() {
|
|
97
|
+
this._clearHideTimeout()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Hides the tooltip when the mouse leaves the tooltip content.
|
|
102
|
+
*/
|
|
103
|
+
contentMouseLeave() {
|
|
104
|
+
this._doHide()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// --- Private ---
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Shows the tooltip immediately: opens the popover, positions it,
|
|
111
|
+
* and triggers the entry animation.
|
|
112
|
+
*
|
|
113
|
+
* @private
|
|
114
|
+
*/
|
|
115
|
+
_doShow() {
|
|
116
|
+
if (this._open) return
|
|
117
|
+
this._open = true
|
|
118
|
+
|
|
119
|
+
this.contentTarget.showPopover()
|
|
120
|
+
this.contentTarget.setAttribute("data-state", "open")
|
|
121
|
+
|
|
122
|
+
const placement = this._buildPlacement()
|
|
123
|
+
const options = {
|
|
124
|
+
placement,
|
|
125
|
+
strategy: "fixed",
|
|
126
|
+
offset: 8,
|
|
127
|
+
}
|
|
128
|
+
if (this.hasArrowTarget) {
|
|
129
|
+
options.arrow = this.arrowTarget
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
this._cleanupPosition = startPositioning(this.triggerTarget, this.contentTarget, options)
|
|
133
|
+
|
|
134
|
+
this.dispatch("show")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Hides the tooltip: triggers exit animation, then hides the popover.
|
|
139
|
+
*
|
|
140
|
+
* @private
|
|
141
|
+
*/
|
|
142
|
+
_doHide() {
|
|
143
|
+
if (!this._open) return
|
|
144
|
+
this._open = false
|
|
145
|
+
|
|
146
|
+
this._cleanupPosition?.()
|
|
147
|
+
this._cleanupPosition = null
|
|
148
|
+
this._clearTimers()
|
|
149
|
+
|
|
150
|
+
this.contentTarget.setAttribute("data-state", "closed")
|
|
151
|
+
|
|
152
|
+
// Hide after exit animation completes
|
|
153
|
+
this._animHandler = () => {
|
|
154
|
+
this.contentTarget.hidePopover()
|
|
155
|
+
this.contentTarget.removeEventListener("animationend", this._animHandler)
|
|
156
|
+
this._animHandler = null
|
|
157
|
+
}
|
|
158
|
+
this.contentTarget.addEventListener("animationend", this._animHandler)
|
|
159
|
+
|
|
160
|
+
// Fallback: hide immediately if no animation runs
|
|
161
|
+
this._closeTimeout = setTimeout(() => {
|
|
162
|
+
if (!this._open && this.contentTarget.matches(":popover-open")) {
|
|
163
|
+
this.contentTarget.hidePopover()
|
|
164
|
+
}
|
|
165
|
+
}, 150)
|
|
166
|
+
|
|
167
|
+
this.dispatch("hide")
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Builds a Floating UI placement string from side and align values.
|
|
172
|
+
*
|
|
173
|
+
* @returns {string} e.g. "top", "top-start", "bottom-end"
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
176
|
+
_buildPlacement() {
|
|
177
|
+
const side = this.sideValue
|
|
178
|
+
const align = this.alignValue
|
|
179
|
+
if (align === "center") return side
|
|
180
|
+
return `${side}-${align}`
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** @private */
|
|
184
|
+
_clearShowTimeout() {
|
|
185
|
+
if (this._showTimeout) {
|
|
186
|
+
clearTimeout(this._showTimeout)
|
|
187
|
+
this._showTimeout = null
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** @private */
|
|
192
|
+
_clearHideTimeout() {
|
|
193
|
+
if (this._hideTimeout) {
|
|
194
|
+
clearTimeout(this._hideTimeout)
|
|
195
|
+
this._hideTimeout = null
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** @private */
|
|
200
|
+
_clearTimers() {
|
|
201
|
+
this._clearShowTimeout()
|
|
202
|
+
this._clearHideTimeout()
|
|
203
|
+
if (this._closeTimeout) {
|
|
204
|
+
clearTimeout(this._closeTimeout)
|
|
205
|
+
this._closeTimeout = null
|
|
206
|
+
}
|
|
207
|
+
if (this._animHandler) {
|
|
208
|
+
this.contentTarget.removeEventListener("animationend", this._animHandler)
|
|
209
|
+
this._animHandler = null
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
* Shared positioning utilities for floating components.
|
|
3
3
|
* Wraps Floating UI for smart positioning with flip, shift, and auto-update.
|
|
4
4
|
*
|
|
5
|
-
* Used by select, combobox, popover, and
|
|
5
|
+
* Used by select, combobox, popover, dropdown_menu, and tooltip controllers.
|
|
6
6
|
*
|
|
7
7
|
* @module utils/positioning
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
arrow as arrowMiddleware,
|
|
12
|
+
autoUpdate,
|
|
13
|
+
computePosition,
|
|
14
|
+
flip,
|
|
15
|
+
offset,
|
|
16
|
+
shift,
|
|
17
|
+
size,
|
|
18
|
+
} from "@floating-ui/dom"
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* Starts positioning a floating element relative to a reference element.
|
|
@@ -24,6 +32,7 @@ import { autoUpdate, computePosition, flip, offset, shift, size } from "@floatin
|
|
|
24
32
|
* @param {number} [options.offset=4] - Pixel gap between reference and floating element
|
|
25
33
|
* @param {"absolute"|"fixed"} [options.strategy="absolute"] - CSS positioning strategy
|
|
26
34
|
* @param {boolean} [options.matchWidth=false] - Set floating element minWidth to reference width
|
|
35
|
+
* @param {HTMLElement|null} [options.arrow=null] - Arrow element to position via Floating UI arrow middleware
|
|
27
36
|
* @returns {Function} Cleanup function — call on close or disconnect to remove listeners
|
|
28
37
|
*
|
|
29
38
|
* @example
|
|
@@ -49,6 +58,7 @@ export function startPositioning(reference, floating, options = {}) {
|
|
|
49
58
|
offset: offsetDistance = 4,
|
|
50
59
|
strategy = "absolute",
|
|
51
60
|
matchWidth = false,
|
|
61
|
+
arrow: arrowElement = null,
|
|
52
62
|
} = options
|
|
53
63
|
|
|
54
64
|
const middleware = [offset(offsetDistance), flip(), shift({ padding: 8 })]
|
|
@@ -63,12 +73,19 @@ export function startPositioning(reference, floating, options = {}) {
|
|
|
63
73
|
)
|
|
64
74
|
}
|
|
65
75
|
|
|
76
|
+
if (arrowElement) {
|
|
77
|
+
middleware.push(arrowMiddleware({ element: arrowElement }))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @type {Record<string, string>} Maps placement side to the opposite side where the arrow attaches */
|
|
81
|
+
const ARROW_STATIC_SIDE = { top: "bottom", right: "left", bottom: "top", left: "right" }
|
|
82
|
+
|
|
66
83
|
const update = () => {
|
|
67
84
|
computePosition(reference, floating, {
|
|
68
85
|
placement,
|
|
69
86
|
strategy,
|
|
70
87
|
middleware,
|
|
71
|
-
}).then(({ x, y, placement: finalPlacement }) => {
|
|
88
|
+
}).then(({ x, y, placement: finalPlacement, middlewareData }) => {
|
|
72
89
|
Object.assign(floating.style, {
|
|
73
90
|
position: strategy,
|
|
74
91
|
left: `${x}px`,
|
|
@@ -79,6 +96,20 @@ export function startPositioning(reference, floating, options = {}) {
|
|
|
79
96
|
if (floating.dataset.side !== side) {
|
|
80
97
|
floating.dataset.side = side
|
|
81
98
|
}
|
|
99
|
+
|
|
100
|
+
// Position arrow element if provided
|
|
101
|
+
if (arrowElement && middlewareData.arrow) {
|
|
102
|
+
const { x: arrowX, y: arrowY } = middlewareData.arrow
|
|
103
|
+
const staticSide = ARROW_STATIC_SIDE[side]
|
|
104
|
+
|
|
105
|
+
Object.assign(arrowElement.style, {
|
|
106
|
+
left: arrowX != null ? `${arrowX}px` : "",
|
|
107
|
+
top: arrowY != null ? `${arrowY}px` : "",
|
|
108
|
+
right: "",
|
|
109
|
+
bottom: "",
|
|
110
|
+
[staticSide]: "-4px",
|
|
111
|
+
})
|
|
112
|
+
}
|
|
82
113
|
})
|
|
83
114
|
}
|
|
84
115
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
<%# locals: (src: nil, alt: "", text: nil, size: :md, ui: {}, css_classes: "", **component_options) %>
|
|
1
|
+
<%# locals: (src: nil, alt: "", text: nil, size: :md, color: nil, ui: {}, css_classes: "", **component_options) %>
|
|
2
2
|
<%= content_tag :span,
|
|
3
3
|
class: Kiso::Themes::Avatar.render(size: size, class: css_classes),
|
|
4
|
+
style: (color ? "background-color: #{color};" : nil),
|
|
4
5
|
data: kiso_prepare_options(component_options, slot: "avatar", size: size),
|
|
5
6
|
**component_options do %>
|
|
6
7
|
<% content = capture { yield }.presence %>
|
|
@@ -8,7 +9,9 @@
|
|
|
8
9
|
<%= content %>
|
|
9
10
|
<% else %>
|
|
10
11
|
<% if text.present? %>
|
|
11
|
-
|
|
12
|
+
<% fallback_classes = ui[:fallback].to_s %>
|
|
13
|
+
<% fallback_classes = "bg-transparent text-inherit #{fallback_classes}" if color %>
|
|
14
|
+
<%= tag.span class: Kiso::Themes::AvatarFallback.render(size: size, class: fallback_classes),
|
|
12
15
|
data: { slot: "avatar-fallback" } do %>
|
|
13
16
|
<%= text %>
|
|
14
17
|
<% end %>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<%# locals: (label: nil, css_classes: "", **component_options) %>
|
|
2
|
+
<%= kiso_component_icon(:spinner,
|
|
3
|
+
role: "status",
|
|
4
|
+
aria: { label: label || t("kiso.spinner.loading") },
|
|
5
|
+
class: Kiso::Themes::Spinner.render(class: css_classes),
|
|
6
|
+
data: kiso_prepare_options(component_options, slot: "spinner"),
|
|
7
|
+
**component_options) %>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<%# locals: (text: nil, kbds: nil, side: :top, align: :center, delay: 0, ui: {}, css_classes: "", **component_options) %>
|
|
2
|
+
<%= tag.div(
|
|
3
|
+
class: css_classes.presence,
|
|
4
|
+
data: kiso_prepare_options(component_options, slot: "tooltip",
|
|
5
|
+
controller: "kiso--tooltip",
|
|
6
|
+
kiso__tooltip_side_value: side,
|
|
7
|
+
kiso__tooltip_align_value: align,
|
|
8
|
+
kiso__tooltip_delay_value: delay),
|
|
9
|
+
**component_options) do %>
|
|
10
|
+
<% if text %>
|
|
11
|
+
<%= kui(:tooltip, :trigger) { yield } %>
|
|
12
|
+
<%= kui(:tooltip, :content, css_classes: ui[:content].to_s) do %>
|
|
13
|
+
<span data-slot="tooltip-text"><%= text %></span>
|
|
14
|
+
<% if kbds.present? %>
|
|
15
|
+
<span data-slot="tooltip-kbds" class="hidden lg:inline-flex items-center shrink-0 gap-0.5">
|
|
16
|
+
<% Array(kbds).each do |kbd| %>
|
|
17
|
+
<%= kui(:kbd, size: :sm) { kbd } %>
|
|
18
|
+
<% end %>
|
|
19
|
+
</span>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
<% else %>
|
|
23
|
+
<%= yield %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<%# locals: (css_classes: "", ui: {}, **component_options) %>
|
|
2
|
+
<%= tag.div(
|
|
3
|
+
class: Kiso::Themes::TooltipContent.render(class: css_classes),
|
|
4
|
+
role: "tooltip",
|
|
5
|
+
popover: "manual",
|
|
6
|
+
data: kiso_prepare_options(component_options, slot: "tooltip-content",
|
|
7
|
+
kiso__tooltip_target: "content",
|
|
8
|
+
action: "mouseenter->kiso--tooltip#contentMouseEnter mouseleave->kiso--tooltip#contentMouseLeave"),
|
|
9
|
+
**component_options) do %>
|
|
10
|
+
<%= yield %>
|
|
11
|
+
<%= tag.div(
|
|
12
|
+
class: Kiso::Themes::TooltipArrow.render(class: ui[:arrow].to_s),
|
|
13
|
+
data: { slot: "tooltip-arrow", kiso__tooltip_target: "arrow" }) %>
|
|
14
|
+
<% end %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<%# locals: (css_classes: "", **component_options) %>
|
|
2
|
+
<%= tag.div(
|
|
3
|
+
class: css_classes.presence,
|
|
4
|
+
data: kiso_prepare_options(component_options, slot: "tooltip-trigger",
|
|
5
|
+
kiso__tooltip_target: "trigger",
|
|
6
|
+
action: "mouseenter->kiso--tooltip#show mouseleave->kiso--tooltip#hide focusin->kiso--tooltip#show focusout->kiso--tooltip#hide"),
|
|
7
|
+
**component_options) do %>
|
|
8
|
+
<%= yield %>
|
|
9
|
+
<% end %>
|
data/config/locales/en.yml
CHANGED
data/lib/kiso/configuration.rb
CHANGED
data/lib/kiso/presets/rounded.rb
CHANGED
|
@@ -130,7 +130,10 @@ module Kiso
|
|
|
130
130
|
nav_item: {base: "rounded-full"},
|
|
131
131
|
|
|
132
132
|
# Nav item badge: rounded-md → rounded-full
|
|
133
|
-
nav_item_badge: {base: "rounded-full"}
|
|
133
|
+
nav_item_badge: {base: "rounded-full"},
|
|
134
|
+
|
|
135
|
+
# Tooltip content: rounded-md → rounded-xl
|
|
136
|
+
tooltip_content: {base: "rounded-xl"}
|
|
134
137
|
}.freeze
|
|
135
138
|
end
|
|
136
139
|
end
|
data/lib/kiso/presets/sharp.rb
CHANGED
|
@@ -172,7 +172,10 @@ module Kiso
|
|
|
172
172
|
nav_item: {base: "rounded-none"},
|
|
173
173
|
|
|
174
174
|
# Nav item badge: rounded-md → rounded-none
|
|
175
|
-
nav_item_badge: {base: "rounded-none"}
|
|
175
|
+
nav_item_badge: {base: "rounded-none"},
|
|
176
|
+
|
|
177
|
+
# Tooltip content: rounded-md → rounded-none
|
|
178
|
+
tooltip_content: {base: "rounded-none"}
|
|
176
179
|
}.freeze
|
|
177
180
|
end
|
|
178
181
|
end
|
data/lib/kiso/themes/avatar.rb
CHANGED
|
@@ -4,6 +4,7 @@ module Kiso
|
|
|
4
4
|
base: "group/avatar relative flex shrink-0 rounded-full select-none items-center justify-center bg-muted",
|
|
5
5
|
variants: {
|
|
6
6
|
size: {
|
|
7
|
+
xs: "size-5",
|
|
7
8
|
sm: "size-6",
|
|
8
9
|
md: "size-8",
|
|
9
10
|
lg: "size-10"
|
|
@@ -20,6 +21,7 @@ module Kiso
|
|
|
20
21
|
base: "flex size-full items-center justify-center rounded-full bg-muted text-muted-foreground font-medium",
|
|
21
22
|
variants: {
|
|
22
23
|
size: {
|
|
24
|
+
xs: "text-[10px]",
|
|
23
25
|
sm: "text-xs",
|
|
24
26
|
md: "text-sm",
|
|
25
27
|
lg: "text-base"
|
|
@@ -31,6 +33,7 @@ module Kiso
|
|
|
31
33
|
AvatarBadge = ClassVariants.build(
|
|
32
34
|
base: "bg-primary text-primary-foreground ring-background absolute right-0 bottom-0 z-10 " \
|
|
33
35
|
"inline-flex items-center justify-center rounded-full ring-2 select-none " \
|
|
36
|
+
"group-data-[size=xs]/avatar:size-1.5 group-data-[size=xs]/avatar:[&>svg]:hidden " \
|
|
34
37
|
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden " \
|
|
35
38
|
"group-data-[size=md]/avatar:size-2.5 group-data-[size=md]/avatar:[&>svg]:size-2 " \
|
|
36
39
|
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2"
|
|
@@ -44,9 +47,11 @@ module Kiso
|
|
|
44
47
|
AvatarGroupCount = ClassVariants.build(
|
|
45
48
|
base: "bg-muted text-muted-foreground ring-background relative flex size-8 shrink-0 " \
|
|
46
49
|
"items-center justify-center rounded-full text-sm ring-2 " \
|
|
50
|
+
"group-has-data-[size=xs]/avatar-group:size-5 " \
|
|
47
51
|
"group-has-data-[size=lg]/avatar-group:size-10 " \
|
|
48
52
|
"group-has-data-[size=sm]/avatar-group:size-6 " \
|
|
49
53
|
"[&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 " \
|
|
54
|
+
"group-has-data-[size=xs]/avatar-group:[&>svg]:size-2.5 " \
|
|
50
55
|
"group-has-data-[size=sm]/avatar-group:[&>svg]:size-3"
|
|
51
56
|
)
|
|
52
57
|
end
|
data/lib/kiso/themes/button.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Kiso
|
|
|
14
14
|
# - +size+ — :xs, :sm, :md (default), :lg, :xl
|
|
15
15
|
# - +block+ — +true+ for full-width, +false+ (default)
|
|
16
16
|
Button = ClassVariants.build(
|
|
17
|
-
base: "
|
|
17
|
+
base: "items-center justify-center gap-2 font-medium whitespace-nowrap shrink-0 " \
|
|
18
18
|
"transition-all " \
|
|
19
19
|
"focus-visible:outline-2 focus-visible:outline-offset-2 " \
|
|
20
20
|
"disabled:pointer-events-none disabled:opacity-50 " \
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Spinning loading indicator.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# Spinner.render
|
|
7
|
+
#
|
|
8
|
+
# No variants — size is controlled via +css_classes:+. Inherits
|
|
9
|
+
# +currentColor+ from the parent context.
|
|
10
|
+
#
|
|
11
|
+
# shadcn base: size-4 animate-spin
|
|
12
|
+
Spinner = ClassVariants.build(
|
|
13
|
+
base: "animate-spin size-4"
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Kiso
|
|
2
|
+
module Themes
|
|
3
|
+
# Floating tooltip content panel with inverted colors.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# TooltipContent.render
|
|
7
|
+
#
|
|
8
|
+
# No variants — tooltip always uses inverted colors. Inherits position
|
|
9
|
+
# from Floating UI via the Stimulus controller.
|
|
10
|
+
#
|
|
11
|
+
# shadcn base: bg-foreground text-background px-3 py-1.5 text-xs rounded-md
|
|
12
|
+
# Kiso: bg-inverted text-inverted-foreground (semantic equivalents)
|
|
13
|
+
TooltipContent = ClassVariants.build(
|
|
14
|
+
base: "bg-inverted text-inverted-foreground px-3 py-1.5 text-xs rounded-md " \
|
|
15
|
+
"flex items-center gap-1.5 select-none w-max max-w-xs"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Arrow element pointing from tooltip content to the trigger.
|
|
19
|
+
#
|
|
20
|
+
# Positioned by Floating UI arrow middleware. CSS rotates 45° to form
|
|
21
|
+
# a diamond, with half hidden behind the tooltip edge.
|
|
22
|
+
TooltipArrow = ClassVariants.build(
|
|
23
|
+
base: "absolute size-2 rotate-45 bg-inverted"
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/kiso/version.rb
CHANGED
data/lib/kiso.rb
CHANGED
|
@@ -49,6 +49,8 @@ require "kiso/themes/nav"
|
|
|
49
49
|
require "kiso/themes/page"
|
|
50
50
|
require "kiso/themes/avatar"
|
|
51
51
|
require "kiso/themes/skeleton"
|
|
52
|
+
require "kiso/themes/spinner"
|
|
53
|
+
require "kiso/themes/tooltip"
|
|
52
54
|
require "kiso/themes/slider"
|
|
53
55
|
require "kiso/themes/layout"
|
|
54
56
|
require "kiso/icons"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kiso
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0.pre
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Steve Clarke
|
|
@@ -73,13 +73,13 @@ executables: []
|
|
|
73
73
|
extensions: []
|
|
74
74
|
extra_rdoc_files: []
|
|
75
75
|
files:
|
|
76
|
-
- CHANGELOG.md
|
|
77
76
|
- MIT-LICENSE
|
|
78
77
|
- README.md
|
|
79
78
|
- Rakefile
|
|
80
79
|
- app/assets/fonts/kiso/GeistMonoVF.woff2
|
|
81
80
|
- app/assets/fonts/kiso/GeistVF.woff2
|
|
82
81
|
- app/assets/fonts/kiso/OFL.txt
|
|
82
|
+
- app/assets/tailwind/kiso/button.css
|
|
83
83
|
- app/assets/tailwind/kiso/checkbox.css
|
|
84
84
|
- app/assets/tailwind/kiso/color-mode.css
|
|
85
85
|
- app/assets/tailwind/kiso/dashboard.css
|
|
@@ -93,6 +93,7 @@ files:
|
|
|
93
93
|
- app/assets/tailwind/kiso/palettes/zinc.css
|
|
94
94
|
- app/assets/tailwind/kiso/radio-group.css
|
|
95
95
|
- app/assets/tailwind/kiso/slider.css
|
|
96
|
+
- app/assets/tailwind/kiso/tooltip.css
|
|
96
97
|
- app/helpers/kiso/app_component_helper.rb
|
|
97
98
|
- app/helpers/kiso/component_helper.rb
|
|
98
99
|
- app/helpers/kiso/icon_helper.rb
|
|
@@ -103,6 +104,7 @@ files:
|
|
|
103
104
|
- app/javascript/controllers/kiso/command_controller.js
|
|
104
105
|
- app/javascript/controllers/kiso/command_dialog_controller.js
|
|
105
106
|
- app/javascript/controllers/kiso/dialog_controller.js
|
|
107
|
+
- app/javascript/controllers/kiso/dialog_trigger_controller.js
|
|
106
108
|
- app/javascript/controllers/kiso/dropdown_menu_controller.js
|
|
107
109
|
- app/javascript/controllers/kiso/index.d.ts
|
|
108
110
|
- app/javascript/controllers/kiso/index.js
|
|
@@ -114,6 +116,7 @@ files:
|
|
|
114
116
|
- app/javascript/controllers/kiso/theme_controller.js
|
|
115
117
|
- app/javascript/controllers/kiso/toggle_controller.js
|
|
116
118
|
- app/javascript/controllers/kiso/toggle_group_controller.js
|
|
119
|
+
- app/javascript/controllers/kiso/tooltip_controller.js
|
|
117
120
|
- app/javascript/kiso/utils/focusable.js
|
|
118
121
|
- app/javascript/kiso/utils/highlight.js
|
|
119
122
|
- app/javascript/kiso/utils/positioning.js
|
|
@@ -168,6 +171,7 @@ files:
|
|
|
168
171
|
- app/views/kiso/components/_separator.html.erb
|
|
169
172
|
- app/views/kiso/components/_skeleton.html.erb
|
|
170
173
|
- app/views/kiso/components/_slider.html.erb
|
|
174
|
+
- app/views/kiso/components/_spinner.html.erb
|
|
171
175
|
- app/views/kiso/components/_stats_card.html.erb
|
|
172
176
|
- app/views/kiso/components/_stats_grid.html.erb
|
|
173
177
|
- app/views/kiso/components/_switch.html.erb
|
|
@@ -175,6 +179,7 @@ files:
|
|
|
175
179
|
- app/views/kiso/components/_textarea.html.erb
|
|
176
180
|
- app/views/kiso/components/_toggle.html.erb
|
|
177
181
|
- app/views/kiso/components/_toggle_group.html.erb
|
|
182
|
+
- app/views/kiso/components/_tooltip.html.erb
|
|
178
183
|
- app/views/kiso/components/alert/_actions.html.erb
|
|
179
184
|
- app/views/kiso/components/alert/_description.html.erb
|
|
180
185
|
- app/views/kiso/components/alert/_title.html.erb
|
|
@@ -320,6 +325,8 @@ files:
|
|
|
320
325
|
- app/views/kiso/components/table/_header.html.erb
|
|
321
326
|
- app/views/kiso/components/table/_row.html.erb
|
|
322
327
|
- app/views/kiso/components/toggle_group/_item.html.erb
|
|
328
|
+
- app/views/kiso/components/tooltip/_content.html.erb
|
|
329
|
+
- app/views/kiso/components/tooltip/_trigger.html.erb
|
|
323
330
|
- config/deploy.docs.yml
|
|
324
331
|
- config/deploy.yml
|
|
325
332
|
- config/importmap.rb
|
|
@@ -380,12 +387,14 @@ files:
|
|
|
380
387
|
- lib/kiso/themes/shared.rb
|
|
381
388
|
- lib/kiso/themes/skeleton.rb
|
|
382
389
|
- lib/kiso/themes/slider.rb
|
|
390
|
+
- lib/kiso/themes/spinner.rb
|
|
383
391
|
- lib/kiso/themes/stats_card.rb
|
|
384
392
|
- lib/kiso/themes/switch.rb
|
|
385
393
|
- lib/kiso/themes/table.rb
|
|
386
394
|
- lib/kiso/themes/textarea.rb
|
|
387
395
|
- lib/kiso/themes/toggle.rb
|
|
388
396
|
- lib/kiso/themes/toggle_group.rb
|
|
397
|
+
- lib/kiso/themes/tooltip.rb
|
|
389
398
|
- lib/kiso/version.rb
|
|
390
399
|
- lib/tasks/kiso.rake
|
|
391
400
|
homepage: https://github.com/steveclarke/kiso
|
|
@@ -394,7 +403,7 @@ licenses:
|
|
|
394
403
|
metadata:
|
|
395
404
|
homepage_uri: https://github.com/steveclarke/kiso
|
|
396
405
|
source_code_uri: https://github.com/steveclarke/kiso
|
|
397
|
-
changelog_uri: https://github.com/steveclarke/kiso/
|
|
406
|
+
changelog_uri: https://github.com/steveclarke/kiso/releases
|
|
398
407
|
bug_tracker_uri: https://github.com/steveclarke/kiso/issues
|
|
399
408
|
rubygems_mfa_required: 'true'
|
|
400
409
|
allowed_push_host: https://rubygems.org
|
data/CHANGELOG.md
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [Unreleased]
|
|
9
|
-
|
|
10
|
-
## [0.4.3.pre] - 2026-03-08
|
|
11
|
-
|
|
12
|
-
### Fixed
|
|
13
|
-
|
|
14
|
-
- `scope:` values now merge into the parent partial's kwargs — previously, scope was pushed onto the stack for sub-parts but not merged into the parent's own strict locals, causing `ActionView::StrictLocalsError`
|
|
15
|
-
- `kui_tag` / `appui_tag` now render correctly without a block — self-closing elements (e.g., status dots, icons) were rendering the options hash as text content instead of HTML attributes
|
|
16
|
-
|
|
17
|
-
## [0.4.2.pre] - 2026-03-08
|
|
18
|
-
|
|
19
|
-
### Added
|
|
20
|
-
|
|
21
|
-
- `scope:` prop for sharing domain locals from parent components to sub-parts — `appui(:room_card, scope: { room: room })` makes `room:` available to all sub-parts automatically without repeating it on every call. Explicit kwargs on sub-part calls override scope values. One level deep only (parent to its own sub-parts).
|
|
22
|
-
|
|
23
|
-
## [0.4.1.pre] - 2026-03-08
|
|
24
|
-
|
|
25
|
-
### Added
|
|
26
|
-
|
|
27
|
-
- `center:` variant on App layout component — `kui(:app, center: true)` applies full-viewport centering for login pages and similar single-focus layouts
|
|
28
|
-
- `kui_tag` / `appui_tag` helpers — collapse the common `content_tag` + `kiso_prepare_options` + theme rendering boilerplate into a single call; component generator templates now use `appui_tag` by default
|
|
29
|
-
- Shade scale auto-wiring — host apps defining `--color-primary-50` through `--color-primary-950` in their Tailwind `@theme` block now automatically feed into Kiso's semantic color tokens (shade 500 for light mode, 400 for dark mode, matching Nuxt UI conventions)
|
|
30
|
-
|
|
31
|
-
### Fixed
|
|
32
|
-
|
|
33
|
-
- Palette CSS files are now importable in host apps — a `kiso:palettes` rake task generates CSS stubs so `@import "../builds/tailwind/kiso/palettes/blue.css"` resolves correctly
|
|
34
|
-
|
|
35
|
-
## [0.4.0.pre] - 2026-03-08
|
|
36
|
-
|
|
37
|
-
### Added
|
|
38
|
-
|
|
39
|
-
- Layout component family: App, Container (4 size variants), Header, Footer, Main
|
|
40
|
-
- Page component family: Page (grid with sidebars), PageHeader, PageBody, PageSection, PageGrid, PageCard (4 variants)
|
|
41
|
-
- `appui()` helper for host app components with `app/themes/` and `app/views/components/`
|
|
42
|
-
- `kiso:framework_component` generator for scaffolding engine components
|
|
43
|
-
- `kiso:component` generator for scaffolding host app components
|
|
44
|
-
- Theme presets: `apply_preset(:rounded)` and `apply_preset(:sharp)`
|
|
45
|
-
- 5 OKLCH color palettes (zinc, blue, green, orange, violet)
|
|
46
|
-
- i18n support: all component strings use `t()` with `config/locales/en.yml`
|
|
47
|
-
- [Building Your Own Components](/guide/building-components) guide — how to wrap Kiso components with domain logic and build standalone components with `appui()`, themes, and sub-parts
|
|
48
|
-
- [Detailed release notes](/releases/batch-merge) with upgrade guide and examples for all new features
|
|
49
|
-
|
|
50
|
-
## [0.3.0.pre] - 2026-03-03
|
|
51
|
-
|
|
52
|
-
### Added
|
|
53
|
-
|
|
54
|
-
- Dialog component — modal dialog wrapping the native `<dialog>` element with `showModal()` for focus trapping and backdrop. Sub-parts: header, title, description, body, footer, close. Entry/exit CSS animations with reduced-motion support. Stimulus controller for programmatic open/close.
|
|
55
|
-
- Alert Dialog component — confirmation dialog that requires an explicit user action (`role="alertdialog"`). Cannot be dismissed by Escape or backdrop click. Sub-parts: header, title, description, media, footer, action, cancel. Size variants (default/sm) with responsive media grid layout. Auto-linked `aria-labelledby` and `aria-describedby`.
|
|
56
|
-
- AspectRatio component — lightweight wrapper that applies an aspect ratio via inline style. Accepts any `ratio:` value (defaults to 16:9).
|
|
57
|
-
- Slider component — range input with track, thumb, and fill styling. Supports min/max/step/value, three sizes (sm/md/lg), and disabled state. Stimulus controller for real-time value display.
|
|
58
|
-
- Empty component `:actions` slot for placing buttons below the description.
|
|
59
|
-
- Button `method:` prop — renders a Rails `button_to` form for DELETE/POST/PUT/PATCH actions while preserving all Button styling.
|
|
60
|
-
- Icons guide added to documentation site.
|
|
61
|
-
|
|
62
|
-
### Fixed
|
|
63
|
-
|
|
64
|
-
- InputOTP slots missing visible border when a separator is placed inside a group.
|
|
65
|
-
- Sidebar header and footer now use `flex-col` layout matching shadcn structure.
|
|
66
|
-
|
|
67
|
-
## [0.2.2.pre] - 2026-03-03
|
|
68
|
-
|
|
69
|
-
### Fixed
|
|
70
|
-
|
|
71
|
-
- Dashboard layout rendering — components called without a block inside a layout (e.g., sidebar toggle, collapse) would capture the entire page template via ERB yield bubbling, breaking the dashboard grid. The `kui()` helper now passes an empty proc to prevent yield from reaching the layout.
|
|
72
|
-
- Dashboard toggle and collapse icon sizing — SVG icons now render at the correct size via `[&>svg]:size-4`.
|
|
73
|
-
|
|
74
|
-
## [0.2.1.pre] - 2026-03-03
|
|
75
|
-
|
|
76
|
-
### Fixed
|
|
77
|
-
|
|
78
|
-
- Propshaft `stylesheet_link_tag :app` compatibility — the Rails 8.1 default `:app` symbol caused Propshaft to serve `tailwindcss-rails` engine CSS stubs directly to the browser, resulting in 404 errors for absolute filesystem paths. Kiso now filters these build-time intermediates from Propshaft's stylesheet resolution automatically. Host apps using either `:app` or explicit `"tailwind"` work correctly.
|
|
79
|
-
|
|
80
|
-
## [0.2.0.pre] - 2026-03-03
|
|
81
|
-
|
|
82
|
-
### Added
|
|
83
|
-
|
|
84
|
-
- InputOTP component — one-time password input with individual character slots, auto-advance, paste support, and mobile SMS autofill via `autocomplete="one-time-code"`. Stimulus controller distributes a single transparent input to visual slot divs. Sub-parts: group, slot, separator. Dispatches `change` and `complete` events for auto-submit workflows.
|
|
85
|
-
- SelectNative component — styled native `<select>` with chevron icon overlay. Variant × size axes matching Input (outline/soft/ghost, sm/md/lg). No JavaScript required.
|
|
86
|
-
- Sidebar state variants — `kui-sidebar-open:` and `kui-sidebar-closed:` custom Tailwind variants for showing/hiding any element based on sidebar open/closed state. Composable with breakpoints (e.g., `kui-sidebar-open:lg:hidden`).
|
|
87
|
-
- Custom toggle icon override — sidebar toggle and collapse buttons accept a block to replace the default icon.
|
|
88
|
-
- Auto body base styles — engine CSS now applies `bg-background text-foreground antialiased` on `<body>` via `@layer base`, so host apps no longer need to add these classes manually.
|
|
89
|
-
|
|
90
|
-
## [0.1.1.pre] - 2026-03-03
|
|
91
|
-
|
|
92
|
-
### Added
|
|
93
|
-
|
|
94
|
-
- Dashboard layout system — sidebar, navbar, panel, toolbar, and nav components with cookie-persisted sidebar state
|
|
95
|
-
- Avatar component with image, fallback, badge, and group support
|
|
96
|
-
- Form components — Field, Label, Input, Textarea, InputGroup, Checkbox, RadioGroup, Switch, Select, Combobox
|
|
97
|
-
- Overlay components — Popover, DropdownMenu, Command palette
|
|
98
|
-
- Navigation components — Breadcrumb, Pagination
|
|
99
|
-
- Element components — Kbd, Toggle, ToggleGroup
|
|
100
|
-
- Dark mode system — `kiso_theme_script` helper, ColorModeButton, ColorModeSelect
|
|
101
|
-
- Floating UI positioning for popovers and dropdowns
|
|
102
|
-
- Global theme overrides via `Kiso.configure`
|
|
103
|
-
- Configurable default icons via `kiso_component_icon`
|
|
104
|
-
- Getting Started guide
|
|
105
|
-
|
|
106
|
-
### Changed
|
|
107
|
-
|
|
108
|
-
- Renamed `kiso()` helper to `kui()` to avoid Rails route proxy collision
|
|
109
|
-
- Renamed `empty_state` to `empty` to match shadcn naming
|
|
110
|
-
- Adopted `data-slot` convention from shadcn v4
|
|
111
|
-
|
|
112
|
-
## [0.1.0.pre] - 2026-02-25
|
|
113
|
-
|
|
114
|
-
### Added
|
|
115
|
-
|
|
116
|
-
- Core engine with `kui()` component helper and `kiso_prepare_options` builder
|
|
117
|
-
- `class_variants` + `tailwind_merge` integration for variant definitions
|
|
118
|
-
- Theme CSS with 7 palettes, surface tokens, and dark mode
|
|
119
|
-
- Badge component (color × variant × size, pill shape, SVG handling)
|
|
120
|
-
- Alert component (color × variant, CSS Grid layout, title/description sub-parts)
|
|
121
|
-
- Button component (6 variants, smart tag, 5 sizes, icon support)
|
|
122
|
-
- Card component (3 variants, 6 sub-parts, shadcn gap-6/py-6 spacing)
|
|
123
|
-
- Separator component (horizontal/vertical, decorative prop)
|
|
124
|
-
- Empty State component (5 sub-parts, media variant)
|
|
125
|
-
- Lookbook component previews
|
|
126
|
-
- Bridgetown documentation site
|
|
127
|
-
|
|
128
|
-
[Unreleased]: https://github.com/steveclarke/kiso/compare/v0.4.3.pre...HEAD
|
|
129
|
-
[0.4.3.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.4.3.pre
|
|
130
|
-
[0.4.2.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.4.2.pre
|
|
131
|
-
[0.4.1.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.4.1.pre
|
|
132
|
-
[0.4.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.4.0.pre
|
|
133
|
-
[0.3.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.3.0.pre
|
|
134
|
-
[0.2.2.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.2.2.pre
|
|
135
|
-
[0.2.1.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.2.1.pre
|
|
136
|
-
[0.2.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.2.0.pre
|
|
137
|
-
[0.1.1.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.1.1.pre
|
|
138
|
-
[0.1.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.1.0.pre
|