@gratiaos/ui 1.0.3 β 1.0.5
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/README.md +13 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useFlowActivity.d.ts +21 -0
- package/dist/hooks/useFlowActivity.d.ts.map +1 -0
- package/dist/hooks/useFlowActivity.js +36 -0
- package/dist/hooks/useFlowActivity.js.map +1 -0
- package/dist/hooks/useSceneTheme.d.ts +20 -0
- package/dist/hooks/useSceneTheme.d.ts.map +1 -0
- package/dist/hooks/useSceneTheme.js +81 -0
- package/dist/hooks/useSceneTheme.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/primitives/whisper.d.ts +46 -0
- package/dist/primitives/whisper.d.ts.map +1 -0
- package/dist/primitives/whisper.js +49 -0
- package/dist/primitives/whisper.js.map +1 -0
- package/package.json +1 -1
- package/styles/base.css +1 -0
- package/styles/pad.css +3 -0
- package/styles/theme.css +12 -0
- package/styles/whisper.css +49 -0
package/README.md
CHANGED
|
@@ -65,6 +65,19 @@ Short purpose notes (see Playground for full demos):
|
|
|
65
65
|
|
|
66
66
|
Each primitive maps to **global design tokens**, so themes and local contexts stay in sync.
|
|
67
67
|
|
|
68
|
+
### πͺ΄ Reactive State (Signals)
|
|
69
|
+
|
|
70
|
+
Garden UI stays headless; it does not bundle a state system. For tiny local reactive values (e.g. live counters, inline mood flags, demo toggles) use the micro primitive `@gratiaos/signal`:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { createSignal } from '@gratiaos/signal';
|
|
74
|
+
const count$ = createSignal(0);
|
|
75
|
+
count$.subscribe((v) => console.log('count', v));
|
|
76
|
+
count$.set(count$.value + 1);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Connect signals to primitives by reading their current value in render and subscribing in effects (or bridging through your own hooks). This keeps UI lean while enabling fine-grained reactivity without a large framework.
|
|
80
|
+
|
|
68
81
|
---
|
|
69
82
|
|
|
70
83
|
## π Toasts (quick start)
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
package/dist/hooks/index.js
CHANGED
package/dist/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type FlowActivityOptions = {
|
|
2
|
+
/** Milliseconds after which inactivity is considered paused. Defaults to 5000. */
|
|
3
|
+
pauseAfterMs?: number;
|
|
4
|
+
/** Callback invoked when the flow pauses. */
|
|
5
|
+
onPause?: () => void;
|
|
6
|
+
/** Callback invoked when the flow resumes after a pause. */
|
|
7
|
+
onResume?: () => void;
|
|
8
|
+
};
|
|
9
|
+
export type FlowActivityHandle = {
|
|
10
|
+
/** Notify the hook that the user is active (typing, drawing, etc.). */
|
|
11
|
+
notifyActivity: () => void;
|
|
12
|
+
/** Whether the flow is currently paused. */
|
|
13
|
+
paused: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Tracks interaction bursts (typing, drawing, etc.) and flips to paused when
|
|
17
|
+
* no activity is observed for `pauseAfterMs`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useFlowActivity(options?: FlowActivityOptions): FlowActivityHandle;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=useFlowActivity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFlowActivity.d.ts","sourceRoot":"","sources":["../../src/hooks/useFlowActivity.ts"],"names":[],"mappings":"AAEA,KAAK,mBAAmB,GAAG;IACzB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,uEAAuE;IACvE,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,4CAA4C;IAC5C,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,mBAAwB,GAAG,kBAAkB,CAkCrF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks interaction bursts (typing, drawing, etc.) and flips to paused when
|
|
4
|
+
* no activity is observed for `pauseAfterMs`.
|
|
5
|
+
*/
|
|
6
|
+
export function useFlowActivity(options = {}) {
|
|
7
|
+
const { pauseAfterMs = 5000 } = options;
|
|
8
|
+
const onPauseRef = React.useRef(options.onPause);
|
|
9
|
+
const onResumeRef = React.useRef(options.onResume);
|
|
10
|
+
onPauseRef.current = options.onPause;
|
|
11
|
+
onResumeRef.current = options.onResume;
|
|
12
|
+
const timerRef = React.useRef(null);
|
|
13
|
+
const [paused, setPaused] = React.useState(true);
|
|
14
|
+
const clearTimer = () => {
|
|
15
|
+
if (timerRef.current !== null) {
|
|
16
|
+
window.clearTimeout(timerRef.current);
|
|
17
|
+
timerRef.current = null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const notifyActivity = React.useCallback(() => {
|
|
21
|
+
clearTimer();
|
|
22
|
+
if (paused) {
|
|
23
|
+
setPaused(false);
|
|
24
|
+
onResumeRef.current?.();
|
|
25
|
+
}
|
|
26
|
+
timerRef.current = window.setTimeout(() => {
|
|
27
|
+
setPaused(true);
|
|
28
|
+
onPauseRef.current?.();
|
|
29
|
+
}, pauseAfterMs);
|
|
30
|
+
}, [pauseAfterMs, paused]);
|
|
31
|
+
React.useEffect(() => {
|
|
32
|
+
return () => clearTimer();
|
|
33
|
+
}, []);
|
|
34
|
+
return { paused, notifyActivity };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=useFlowActivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFlowActivity.js","sourceRoot":"","sources":["../../src/hooks/useFlowActivity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAkB/B;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,UAA+B,EAAE;IAC/D,MAAM,EAAE,YAAY,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnD,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACrC,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAEvC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAgB,IAAI,CAAC,CAAC;IACnD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEjD,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC9B,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACtC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC5C,UAAU,EAAE,CAAC;QACb,IAAI,MAAM,EAAE,CAAC;YACX,SAAS,CAAC,KAAK,CAAC,CAAC;YACjB,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1B,CAAC;QACD,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;YACxC,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;QACzB,CAAC,EAAE,YAAY,CAAC,CAAC;IACnB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAE3B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,OAAO,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type SceneThemeOptions = {
|
|
2
|
+
/** CSS token or value for the base/background color. */
|
|
3
|
+
base?: string;
|
|
4
|
+
/** Accent color token/value for highlights. */
|
|
5
|
+
accent?: string;
|
|
6
|
+
/** Optional depth (0..1) passed to data attribute for skins. */
|
|
7
|
+
depth?: number;
|
|
8
|
+
/** Additional custom CSS variables. */
|
|
9
|
+
vars?: Record<string, string | number>;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Scene theming hook
|
|
13
|
+
* ------------------
|
|
14
|
+
* Applies scene-specific CSS variables / data attributes at the document level.
|
|
15
|
+
*
|
|
16
|
+
* Call inside scene components to tint the Garden for the current mood.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useSceneTheme(scene: string | null | undefined, options?: SceneThemeOptions): void;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=useSceneTheme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSceneTheme.d.ts","sourceRoot":"","sources":["../../src/hooks/useSceneTheme.ts"],"names":[],"mappings":"AAEA,KAAK,iBAAiB,GAAG;IACvB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CACxC,CAAC;AA0DF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,GAAE,iBAAsB,QAc9F"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** Keeps prior scene theme values so we can restore them on cleanup. */
|
|
3
|
+
function snapshotTheme(root) {
|
|
4
|
+
return {
|
|
5
|
+
scene: root.dataset.sceneTheme,
|
|
6
|
+
depth: root.dataset.sceneDepth,
|
|
7
|
+
base: root.style.getPropertyValue('--scene-base'),
|
|
8
|
+
accent: root.style.getPropertyValue('--scene-accent'),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function applyTheme(root, scene, options) {
|
|
12
|
+
root.dataset.sceneTheme = scene;
|
|
13
|
+
if (options.depth !== undefined) {
|
|
14
|
+
root.dataset.sceneDepth = String(options.depth);
|
|
15
|
+
}
|
|
16
|
+
if (options.base !== undefined) {
|
|
17
|
+
root.style.setProperty('--scene-base', options.base);
|
|
18
|
+
}
|
|
19
|
+
if (options.accent !== undefined) {
|
|
20
|
+
root.style.setProperty('--scene-accent', options.accent);
|
|
21
|
+
}
|
|
22
|
+
if (options.vars) {
|
|
23
|
+
for (const [key, value] of Object.entries(options.vars)) {
|
|
24
|
+
root.style.setProperty(`--${key}`, String(value));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function restoreTheme(root, snapshot, customVars) {
|
|
29
|
+
if (snapshot.scene) {
|
|
30
|
+
root.dataset.sceneTheme = snapshot.scene;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
delete root.dataset.sceneTheme;
|
|
34
|
+
}
|
|
35
|
+
if (snapshot.depth) {
|
|
36
|
+
root.dataset.sceneDepth = snapshot.depth;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
delete root.dataset.sceneDepth;
|
|
40
|
+
}
|
|
41
|
+
if (snapshot.base) {
|
|
42
|
+
root.style.setProperty('--scene-base', snapshot.base);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
root.style.removeProperty('--scene-base');
|
|
46
|
+
}
|
|
47
|
+
if (snapshot.accent) {
|
|
48
|
+
root.style.setProperty('--scene-accent', snapshot.accent);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
root.style.removeProperty('--scene-accent');
|
|
52
|
+
}
|
|
53
|
+
if (customVars) {
|
|
54
|
+
for (const key of Object.keys(customVars)) {
|
|
55
|
+
root.style.removeProperty(`--${key}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Scene theming hook
|
|
61
|
+
* ------------------
|
|
62
|
+
* Applies scene-specific CSS variables / data attributes at the document level.
|
|
63
|
+
*
|
|
64
|
+
* Call inside scene components to tint the Garden for the current mood.
|
|
65
|
+
*/
|
|
66
|
+
export function useSceneTheme(scene, options = {}) {
|
|
67
|
+
const optionsRef = React.useRef(options);
|
|
68
|
+
optionsRef.current = options;
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
if (typeof document === 'undefined' || !scene)
|
|
71
|
+
return;
|
|
72
|
+
const root = document.documentElement;
|
|
73
|
+
const snapshot = snapshotTheme(root);
|
|
74
|
+
const opts = optionsRef.current;
|
|
75
|
+
applyTheme(root, scene, opts);
|
|
76
|
+
return () => {
|
|
77
|
+
restoreTheme(root, snapshot, opts.vars);
|
|
78
|
+
};
|
|
79
|
+
}, [scene]);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=useSceneTheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSceneTheme.js","sourceRoot":"","sources":["../../src/hooks/useSceneTheme.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ export * from './primitives/card.js';
|
|
|
5
5
|
export * from './primitives/field.js';
|
|
6
6
|
export * from './primitives/badge.js';
|
|
7
7
|
export * from './primitives/toast.js';
|
|
8
|
+
export * from './primitives/whisper.js';
|
|
8
9
|
export * from './hooks/index.js';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,5 +5,6 @@ export * from './primitives/card.js';
|
|
|
5
5
|
export * from './primitives/field.js';
|
|
6
6
|
export * from './primitives/badge.js';
|
|
7
7
|
export * from './primitives/toast.js';
|
|
8
|
+
export * from './primitives/whisper.js';
|
|
8
9
|
export * from './hooks/index.js';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Garden UI β Whisper primitive (headless)
|
|
3
|
+
* ---------------------------------------
|
|
4
|
+
* Whisper: "gentle cues keep motion kind." π¬οΈ
|
|
5
|
+
*
|
|
6
|
+
* Purpose
|
|
7
|
+
* β’ Surface soft guidance copy without stealing layout focus.
|
|
8
|
+
* β’ Provide a micro pulse when the message changes so humans notice calmly.
|
|
9
|
+
*
|
|
10
|
+
* Data API
|
|
11
|
+
* β’ [data-ui="whisper"] β root element for skins.
|
|
12
|
+
* β’ [data-tone="intimate|collaborative|presence|β¦"] β drives color and typography.
|
|
13
|
+
* β’ [data-pulsing="true"] β short-lived flag to animate tone shifts.
|
|
14
|
+
*
|
|
15
|
+
* A11y
|
|
16
|
+
* β’ Renders a neutral <div>; copy should remain descriptive (no buttons hidden inside).
|
|
17
|
+
* β’ Pulse uses non-blocking CSS animation and never toggles aria-live regions.
|
|
18
|
+
*
|
|
19
|
+
* Theming
|
|
20
|
+
* β’ Skins read tone + pulsing to set color, glow, and micro motion.
|
|
21
|
+
*
|
|
22
|
+
* Notes
|
|
23
|
+
* β’ Keep pulses short (<300ms) so it feels like a breath, not a notification.
|
|
24
|
+
* β’ Export stays headless β visuals live in styles/whisper.css.
|
|
25
|
+
*/
|
|
26
|
+
import * as React from 'react';
|
|
27
|
+
export type WhisperTone = 'intimate' | 'collaborative' | 'presence' | (string & {});
|
|
28
|
+
export interface WhisperProps {
|
|
29
|
+
/** Whisper text when not using children. */
|
|
30
|
+
text?: React.ReactNode;
|
|
31
|
+
/** Optional render content (overrides `text`). */
|
|
32
|
+
children?: React.ReactNode;
|
|
33
|
+
/** Visual tone (drives CSS hooks). */
|
|
34
|
+
tone?: WhisperTone;
|
|
35
|
+
/** Whether to animate a micro pulse when content changes. Defaults to true. */
|
|
36
|
+
pulseOnChange?: boolean;
|
|
37
|
+
/** Optional className forwarded to the root element. */
|
|
38
|
+
className?: string;
|
|
39
|
+
/** Called whenever the visible content changes. */
|
|
40
|
+
onChange?: () => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Whisper β soft text cue with micro pulse when content shifts.
|
|
44
|
+
*/
|
|
45
|
+
export declare const Whisper: React.ForwardRefExoticComponent<WhisperProps & React.RefAttributes<HTMLDivElement>>;
|
|
46
|
+
//# sourceMappingURL=whisper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whisper.d.ts","sourceRoot":"","sources":["../../src/primitives/whisper.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,eAAe,GAAG,UAAU,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEpF,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,sCAAsC;IACtC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,qFA4BlB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Garden UI β Whisper primitive (headless)
|
|
4
|
+
* ---------------------------------------
|
|
5
|
+
* Whisper: "gentle cues keep motion kind." π¬οΈ
|
|
6
|
+
*
|
|
7
|
+
* Purpose
|
|
8
|
+
* β’ Surface soft guidance copy without stealing layout focus.
|
|
9
|
+
* β’ Provide a micro pulse when the message changes so humans notice calmly.
|
|
10
|
+
*
|
|
11
|
+
* Data API
|
|
12
|
+
* β’ [data-ui="whisper"] β root element for skins.
|
|
13
|
+
* β’ [data-tone="intimate|collaborative|presence|β¦"] β drives color and typography.
|
|
14
|
+
* β’ [data-pulsing="true"] β short-lived flag to animate tone shifts.
|
|
15
|
+
*
|
|
16
|
+
* A11y
|
|
17
|
+
* β’ Renders a neutral <div>; copy should remain descriptive (no buttons hidden inside).
|
|
18
|
+
* β’ Pulse uses non-blocking CSS animation and never toggles aria-live regions.
|
|
19
|
+
*
|
|
20
|
+
* Theming
|
|
21
|
+
* β’ Skins read tone + pulsing to set color, glow, and micro motion.
|
|
22
|
+
*
|
|
23
|
+
* Notes
|
|
24
|
+
* β’ Keep pulses short (<300ms) so it feels like a breath, not a notification.
|
|
25
|
+
* β’ Export stays headless β visuals live in styles/whisper.css.
|
|
26
|
+
*/
|
|
27
|
+
import * as React from 'react';
|
|
28
|
+
/**
|
|
29
|
+
* Whisper β soft text cue with micro pulse when content shifts.
|
|
30
|
+
*/
|
|
31
|
+
export const Whisper = React.forwardRef(function Whisper({ text, children, tone = 'intimate', pulseOnChange = true, className, onChange }, ref) {
|
|
32
|
+
const content = children ?? text;
|
|
33
|
+
const [pulsing, setPulsing] = React.useState(false);
|
|
34
|
+
const lastContent = React.useRef(content);
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (content === lastContent.current)
|
|
37
|
+
return;
|
|
38
|
+
lastContent.current = content;
|
|
39
|
+
onChange?.();
|
|
40
|
+
if (!pulseOnChange)
|
|
41
|
+
return;
|
|
42
|
+
setPulsing(true);
|
|
43
|
+
const id = window.setTimeout(() => setPulsing(false), 260);
|
|
44
|
+
return () => window.clearTimeout(id);
|
|
45
|
+
}, [content, pulseOnChange, onChange]);
|
|
46
|
+
return (_jsx("div", { ref: ref, "data-ui": "whisper", "data-tone": tone, "data-pulsing": pulsing ? 'true' : undefined, className: className, children: content }));
|
|
47
|
+
});
|
|
48
|
+
Whisper.displayName = 'Whisper';
|
|
49
|
+
//# sourceMappingURL=whisper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whisper.js","sourceRoot":"","sources":["../../src/primitives/whisper.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAA+B,SAAS,OAAO,CACpF,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAG,UAAU,EAAE,aAAa,GAAG,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,EAChF,GAAG;IAEH,MAAM,OAAO,GAAG,QAAQ,IAAI,IAAI,CAAC;IACjC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAkB,OAAO,CAAC,CAAC;IAE3D,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,OAAO,KAAK,WAAW,CAAC,OAAO;YAAE,OAAO;QAC5C,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC;QAC9B,QAAQ,EAAE,EAAE,CAAC;QACb,IAAI,CAAC,aAAa;YAAE,OAAO;QAC3B,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3D,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvC,OAAO,CACL,cACE,GAAG,EAAE,GAAG,aACA,SAAS,eACN,IAAI,kBACD,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAC1C,SAAS,EAAE,SAAS,YACnB,OAAO,GACJ,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC"}
|
package/package.json
CHANGED
package/styles/base.css
CHANGED
package/styles/pad.css
CHANGED
package/styles/theme.css
CHANGED
|
@@ -36,6 +36,18 @@
|
|
|
36
36
|
--color-subtle: color-mix(in oklab, var(--color-text) 60%, transparent);
|
|
37
37
|
--color-faint: color-mix(in oklab, var(--color-text) 45%, transparent);
|
|
38
38
|
|
|
39
|
+
/* Tone fade neutrals (scene transitions) */
|
|
40
|
+
--tone-transition-duration: 800ms;
|
|
41
|
+
--tone-transition: background var(--tone-transition-duration) var(--ease-soft, ease), color var(--tone-transition-duration) var(--ease-soft, ease);
|
|
42
|
+
--tone-neutral-surface: color-mix(in oklab, var(--color-surface) 70%, var(--color-accent) 30%);
|
|
43
|
+
--tone-neutral-text: color-mix(in oklab, var(--color-text) 65%, var(--color-accent) 35%);
|
|
44
|
+
|
|
45
|
+
/* Phase hues (used by presence dots + HUD) */
|
|
46
|
+
--phase-companion-hue: 160; /* trust / green */
|
|
47
|
+
--phase-presence-hue: 210; /* clarity / blue */
|
|
48
|
+
--phase-archive-hue: 330; /* reflection / violet */
|
|
49
|
+
--hud-glow-strength: 0.45; /* HUD glow strength */
|
|
50
|
+
|
|
39
51
|
/* Radius & shadow (custom; shadow-* namespace only generates when named accordingly) */
|
|
40
52
|
--radius-pill: 9999px;
|
|
41
53
|
--radius-2xl: 1.25rem;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
2
|
+
Garden UI β Whisper skin (optβin)
|
|
3
|
+
Whisper: "gentle cues stay soft even when shared." π¬οΈ
|
|
4
|
+
|
|
5
|
+
Purpose
|
|
6
|
+
β’ Selector-only skin for the headless Whisper primitive.
|
|
7
|
+
β’ Keeps guidance text light while tone drives color emphasis.
|
|
8
|
+
|
|
9
|
+
Data API
|
|
10
|
+
β’ [data-ui='whisper'] β root wrapper
|
|
11
|
+
β’ [data-tone='intimate|collaborative|presence|β¦']
|
|
12
|
+
β’ [data-pulsing='true'] β transient pulse when copy changes
|
|
13
|
+
|
|
14
|
+
A11y & Motion
|
|
15
|
+
β’ Uppercase + letter-spacing keeps micro copy legible without heavy weight.
|
|
16
|
+
β’ Pulse is 260ms translate/opacity; respects reduced motion (no infinite keyframes).
|
|
17
|
+
β’ Inline-flex layout keeps emoji or icons aligned, avoiding unexpected line height shifts.
|
|
18
|
+
|
|
19
|
+
Theming notes
|
|
20
|
+
β’ Uses color-mix with Garden tokens (accent/positive) rather than raw hex.
|
|
21
|
+
β’ Typography defers to --font-body and --text-sm for consistency.
|
|
22
|
+
|
|
23
|
+
Future ideas
|
|
24
|
+
β’ Additional tone swatches (e.g., grounded/alert) as the whisper library grows.
|
|
25
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
26
|
+
@layer components {
|
|
27
|
+
[data-ui="whisper"] {
|
|
28
|
+
font-size: var(--text-sm);
|
|
29
|
+
color: color-mix(in oklab, var(--color-accent) 70%, var(--color-text) 30%);
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
opacity: 0.88;
|
|
33
|
+
transition: transform var(--duration-snug, 160ms) var(--ease-soft, ease), opacity 200ms var(--ease-soft, ease);
|
|
34
|
+
font-style: italic;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-ui="whisper"][data-tone="collaborative"] {
|
|
38
|
+
color: color-mix(in oklab, var(--color-positive) 70%, var(--color-text) 30%);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
[data-ui="whisper"][data-tone="presence"] {
|
|
42
|
+
color: color-mix(in oklab, var(--color-accent) 80%, var(--color-surface) 20%);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[data-ui="whisper"][data-pulsing="true"] {
|
|
46
|
+
transform: translateY(-2px);
|
|
47
|
+
opacity: 1;
|
|
48
|
+
}
|
|
49
|
+
}
|