@kolkrabbi/kol-component 0.224.0 → 0.226.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/package.json +2 -2
- package/src/atoms/ColorSwatch.jsx +6 -2
- package/src/atoms/SelectionOverlay.jsx +3 -1
- package/src/atoms/XYPad.jsx +4 -4
- package/src/index.js +1 -1
- package/src/molecules/ColorInputRow.jsx +3 -2
- package/src/molecules/Dropdown.jsx +10 -5
- package/src/molecules/FieldRow.jsx +2 -2
- package/src/molecules/InspectorSection.jsx +14 -3
- package/src/molecules/MenuItem.jsx +5 -5
- package/src/molecules/SearchInput.jsx +1 -1
- package/src/molecules/SectionText.jsx +21 -4
- package/src/molecules/ShapeDropdown.jsx +3 -2
- package/src/molecules/SplitToolButton.jsx +3 -2
- package/src/molecules/Stepper.jsx +2 -2
- package/src/molecules/SwatchControls.jsx +3 -1
- package/src/molecules/TabsRow.jsx +1 -1
- package/src/organisms/Canvas.jsx +15 -7
- package/src/organisms/DocumentEditor.jsx +8 -5
- package/src/organisms/KeyframeEditor.jsx +4 -3
- package/src/organisms/LayerStack.jsx +11 -6
- package/src/organisms/MediaLibrary.jsx +1 -1
- package/src/organisms/MediaLibraryExplorer.jsx +67 -3
- package/src/organisms/MediaLibraryPages.jsx +113 -62
- package/src/organisms/RecordManager.jsx +2 -2
- package/src/organisms/SettingsPanel.jsx +5 -1
- package/src/organisms/SettingsSections.jsx +2 -1
- package/src/organisms/SpectrumGrid.jsx +3 -2
- package/src/organisms/TimelineDock.jsx +7 -4
- package/src/organisms/ToolPalette.jsx +6 -3
- package/src/utilities/Popover.jsx +61 -11
- package/src/utilities/QuadrantSync.jsx +3 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createContext, useContext, useState } from 'react'
|
|
2
|
-
import { toneClass } from './tone.js'
|
|
1
|
+
import { cloneElement, createContext, isValidElement, useContext, useLayoutEffect, useState, version as reactVersion } from 'react'
|
|
2
|
+
import { toneClass, TONE_VARS } from './tone.js'
|
|
3
3
|
import {
|
|
4
4
|
useFloating,
|
|
5
5
|
autoUpdate,
|
|
@@ -136,13 +136,29 @@ export function usePopover({
|
|
|
136
136
|
* — the innermost wins, as the native `title` it replaced behaved. */
|
|
137
137
|
const TooltipNest = createContext(null)
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
/* `asChild` (the native-title sweep, 2026-09-26): the tooltip attaches to its one child element
|
|
140
|
+
* instead of wrapping it in a span — for a trigger whose box IS the layout (a grid cell, a rail row,
|
|
141
|
+
* an absolutely placed handle), where an inline-flex wrapper would move it. The child must be an
|
|
142
|
+
* element that takes a ref: an intrinsic tag always does; a component only if it forwards one
|
|
143
|
+
* (React 18 needs forwardRef), so Button / IconFrame keep the wrapper. Its own ref and handlers are
|
|
144
|
+
* kept — the reference props merge over the child's. */
|
|
145
|
+
const childRefOf = (el) => ('ref' in (el.props ?? {}) ? el.props.ref : reactVersion.startsWith('18') ? el.ref : undefined)
|
|
146
|
+
|
|
147
|
+
export function Tooltip(props) {
|
|
148
|
+
/* no label → no tooltip: several call sites pass an optional hint, and an empty panel is worse
|
|
149
|
+
* than none. A separate component so the hooks below never run conditionally. */
|
|
150
|
+
if (props.label == null || props.label === '') return props.children
|
|
151
|
+
return <TooltipOn {...props} />
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function TooltipOn({
|
|
140
155
|
label,
|
|
141
156
|
shortcut,
|
|
142
157
|
placement = 'bottom',
|
|
143
158
|
offset = 6,
|
|
144
159
|
children,
|
|
145
160
|
triggerClassName = 'inline-flex',
|
|
161
|
+
asChild = false,
|
|
146
162
|
}) {
|
|
147
163
|
const [open, setOpen] = useState(false)
|
|
148
164
|
const [covered, setCovered] = useState(false)
|
|
@@ -158,22 +174,56 @@ export function Tooltip({
|
|
|
158
174
|
focus: true,
|
|
159
175
|
})
|
|
160
176
|
|
|
177
|
+
/* THE TONE OF WHERE IT IS (user, 2026-09-26: "tooltip should probably use same tone as dropdowns
|
|
178
|
+
* and buttons"). The panel is portalled to body, outside the `kol-tone-*` wrapper that tones the
|
|
179
|
+
* controls around the trigger — Dropdown's problem, solved the same way: on open, copy the
|
|
180
|
+
* trigger's RESOLVED `--kol-tone-*` onto the panel. No tone in effect = nothing copied, and the
|
|
181
|
+
* tooltip keeps its own surface. */
|
|
182
|
+
const [ambient, setAmbient] = useState(null)
|
|
183
|
+
const shown = open && !covered
|
|
184
|
+
useLayoutEffect(() => {
|
|
185
|
+
const ref = popover.refs.reference.current
|
|
186
|
+
/* the SURROUNDINGS' tone, not the trigger's own: an `asChild` trigger can be a variant button
|
|
187
|
+
* (`kol-btn-ghost` carries its own `--kol-tone-*`), so read its parent; the wrapper span has no
|
|
188
|
+
* variant and inherits the ambient values as it is */
|
|
189
|
+
const el = asChild ? ref?.parentElement : ref
|
|
190
|
+
if (!shown || !(el instanceof Element)) return
|
|
191
|
+
const cs = getComputedStyle(el)
|
|
192
|
+
const vars = {}
|
|
193
|
+
for (const v of TONE_VARS) { const val = cs.getPropertyValue(v).trim(); if (val) vars[v] = val }
|
|
194
|
+
setAmbient(vars)
|
|
195
|
+
}, [shown]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
196
|
+
|
|
197
|
+
const child = asChild && isValidElement(children) ? children : null
|
|
198
|
+
const childRef = child ? childRefOf(child) : undefined
|
|
199
|
+
const setRef = (node) => {
|
|
200
|
+
popover.refs.setReference(node)
|
|
201
|
+
if (typeof childRef === 'function') childRef(node)
|
|
202
|
+
else if (childRef) childRef.current = node
|
|
203
|
+
}
|
|
161
204
|
return (
|
|
162
205
|
<>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
<
|
|
169
|
-
|
|
206
|
+
{child ? (
|
|
207
|
+
<TooltipNest.Provider value={setCovered}>
|
|
208
|
+
{cloneElement(child, { ...popover.getReferenceProps(child.props), ref: setRef })}
|
|
209
|
+
</TooltipNest.Provider>
|
|
210
|
+
) : (
|
|
211
|
+
<span
|
|
212
|
+
ref={popover.refs.setReference}
|
|
213
|
+
{...popover.getReferenceProps()}
|
|
214
|
+
className={triggerClassName}
|
|
215
|
+
>
|
|
216
|
+
<TooltipNest.Provider value={setCovered}>{children}</TooltipNest.Provider>
|
|
217
|
+
</span>
|
|
218
|
+
)}
|
|
170
219
|
<PopoverPanel
|
|
171
220
|
popover={popover}
|
|
172
221
|
focus={false}
|
|
173
222
|
panel={false}
|
|
174
223
|
className="kol-tooltip"
|
|
224
|
+
style={ambient ?? undefined}
|
|
175
225
|
>
|
|
176
|
-
<span
|
|
226
|
+
<span>{label}</span>
|
|
177
227
|
{shortcut && <span className="kol-tooltip-key">{shortcut}</span>}
|
|
178
228
|
</PopoverPanel>
|
|
179
229
|
</>
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
41
|
+
import { Tooltip } from './Popover.jsx'
|
|
41
42
|
|
|
42
43
|
/* ── coordinates ─────────────────────────────────────────────────────────
|
|
43
44
|
* Pure. No DOM writes. The invariant everything rests on: a cell is a
|
|
@@ -442,14 +443,15 @@ export default function QuadrantSync ({
|
|
|
442
443
|
className="kol-mono-12 text-fg-96 bg-fg-04 border border-fg-16"
|
|
443
444
|
style={{ width: 52, padding: '5px 6px', textAlign: 'center', borderRadius: 4 }}
|
|
444
445
|
/>
|
|
446
|
+
<Tooltip label="Set divisions so cells come out square at the current size" asChild>
|
|
445
447
|
<button
|
|
446
448
|
type="button" onClick={applySquare}
|
|
447
|
-
title="Set divisions so cells come out square at the current size"
|
|
448
449
|
className="kol-helper-10 text-fg-96 border border-fg-16"
|
|
449
450
|
style={{ marginLeft: 'auto', padding: '5px 9px', borderRadius: 4, background: 'transparent', cursor: 'pointer' }}
|
|
450
451
|
>
|
|
451
452
|
square
|
|
452
453
|
</button>
|
|
454
|
+
</Tooltip>
|
|
453
455
|
</div>
|
|
454
456
|
{aspect && (
|
|
455
457
|
<div className="kol-mono-10 text-fg-48" style={{ marginTop: 6 }}>
|