@kushagradhawan/kookie-ui 0.1.70 → 0.1.72
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 +4 -0
- package/components.css +63 -380
- package/dist/cjs/components/_internal/base-button.d.ts.map +1 -1
- package/dist/cjs/components/_internal/base-button.js +1 -1
- package/dist/cjs/components/_internal/base-button.js.map +3 -3
- package/dist/cjs/components/_internal/shell-bottom.d.ts +2 -21
- package/dist/cjs/components/_internal/shell-bottom.d.ts.map +1 -1
- package/dist/cjs/components/_internal/shell-bottom.js +1 -1
- package/dist/cjs/components/_internal/shell-bottom.js.map +3 -3
- package/dist/cjs/components/_internal/shell-inspector.d.ts +10 -21
- package/dist/cjs/components/_internal/shell-inspector.d.ts.map +1 -1
- package/dist/cjs/components/_internal/shell-inspector.js +1 -1
- package/dist/cjs/components/_internal/shell-inspector.js.map +3 -3
- package/dist/cjs/components/_internal/shell-prop-helpers.d.ts +7 -0
- package/dist/cjs/components/_internal/shell-prop-helpers.d.ts.map +1 -0
- package/dist/cjs/components/_internal/shell-prop-helpers.js +2 -0
- package/dist/cjs/components/_internal/shell-prop-helpers.js.map +7 -0
- package/dist/cjs/components/_internal/shell-sidebar.d.ts +4 -21
- package/dist/cjs/components/_internal/shell-sidebar.d.ts.map +1 -1
- package/dist/cjs/components/_internal/shell-sidebar.js +1 -1
- package/dist/cjs/components/_internal/shell-sidebar.js.map +3 -3
- package/dist/cjs/components/button.d.ts.map +1 -1
- package/dist/cjs/components/button.js +1 -1
- package/dist/cjs/components/button.js.map +3 -3
- package/dist/cjs/components/chatbar.d.ts +11 -2
- package/dist/cjs/components/chatbar.d.ts.map +1 -1
- package/dist/cjs/components/chatbar.js +1 -1
- package/dist/cjs/components/chatbar.js.map +3 -3
- package/dist/cjs/components/icon-button.d.ts.map +1 -1
- package/dist/cjs/components/icon-button.js +2 -2
- package/dist/cjs/components/icon-button.js.map +3 -3
- package/dist/cjs/components/schemas/shell.schema.d.ts +70 -70
- package/dist/cjs/components/shell.context.d.ts +1 -0
- package/dist/cjs/components/shell.context.d.ts.map +1 -1
- package/dist/cjs/components/shell.context.js.map +2 -2
- package/dist/cjs/components/shell.d.ts +6 -26
- package/dist/cjs/components/shell.d.ts.map +1 -1
- package/dist/cjs/components/shell.hooks.d.ts +19 -2
- package/dist/cjs/components/shell.hooks.d.ts.map +1 -1
- package/dist/cjs/components/shell.hooks.js +1 -1
- package/dist/cjs/components/shell.hooks.js.map +3 -3
- package/dist/cjs/components/shell.js +1 -1
- package/dist/cjs/components/shell.js.map +3 -3
- package/dist/cjs/components/shell.types.d.ts +21 -0
- package/dist/cjs/components/shell.types.d.ts.map +1 -1
- package/dist/cjs/components/shell.types.js +1 -1
- package/dist/cjs/components/shell.types.js.map +2 -2
- package/dist/cjs/components/toggle-button.d.ts.map +1 -1
- package/dist/cjs/components/toggle-button.js +1 -1
- package/dist/cjs/components/toggle-button.js.map +3 -3
- package/dist/cjs/components/toggle-icon-button.d.ts.map +1 -1
- package/dist/cjs/components/toggle-icon-button.js +1 -1
- package/dist/cjs/components/toggle-icon-button.js.map +3 -3
- package/dist/cjs/hooks/index.d.ts +2 -0
- package/dist/cjs/hooks/index.d.ts.map +1 -1
- package/dist/cjs/hooks/index.js +1 -1
- package/dist/cjs/hooks/index.js.map +3 -3
- package/dist/cjs/hooks/use-live-announcer.d.ts.map +1 -1
- package/dist/cjs/hooks/use-live-announcer.js +2 -2
- package/dist/cjs/hooks/use-live-announcer.js.map +3 -3
- package/dist/cjs/hooks/use-toggle-state.d.ts +37 -0
- package/dist/cjs/hooks/use-toggle-state.d.ts.map +1 -0
- package/dist/cjs/hooks/use-toggle-state.js +2 -0
- package/dist/cjs/hooks/use-toggle-state.js.map +7 -0
- package/dist/cjs/hooks/use-tooltip-wrapper.d.ts +29 -0
- package/dist/cjs/hooks/use-tooltip-wrapper.d.ts.map +1 -0
- package/dist/cjs/hooks/use-tooltip-wrapper.js +2 -0
- package/dist/cjs/hooks/use-tooltip-wrapper.js.map +7 -0
- package/dist/esm/components/_internal/base-button.d.ts.map +1 -1
- package/dist/esm/components/_internal/base-button.js +1 -1
- package/dist/esm/components/_internal/base-button.js.map +3 -3
- package/dist/esm/components/_internal/shell-bottom.d.ts +2 -21
- package/dist/esm/components/_internal/shell-bottom.d.ts.map +1 -1
- package/dist/esm/components/_internal/shell-bottom.js +1 -1
- package/dist/esm/components/_internal/shell-bottom.js.map +3 -3
- package/dist/esm/components/_internal/shell-inspector.d.ts +10 -21
- package/dist/esm/components/_internal/shell-inspector.d.ts.map +1 -1
- package/dist/esm/components/_internal/shell-inspector.js +1 -1
- package/dist/esm/components/_internal/shell-inspector.js.map +3 -3
- package/dist/esm/components/_internal/shell-prop-helpers.d.ts +7 -0
- package/dist/esm/components/_internal/shell-prop-helpers.d.ts.map +1 -0
- package/dist/esm/components/_internal/shell-prop-helpers.js +2 -0
- package/dist/esm/components/_internal/shell-prop-helpers.js.map +7 -0
- package/dist/esm/components/_internal/shell-sidebar.d.ts +4 -21
- package/dist/esm/components/_internal/shell-sidebar.d.ts.map +1 -1
- package/dist/esm/components/_internal/shell-sidebar.js +1 -1
- package/dist/esm/components/_internal/shell-sidebar.js.map +3 -3
- package/dist/esm/components/button.d.ts.map +1 -1
- package/dist/esm/components/button.js +1 -1
- package/dist/esm/components/button.js.map +3 -3
- package/dist/esm/components/chatbar.d.ts +11 -2
- package/dist/esm/components/chatbar.d.ts.map +1 -1
- package/dist/esm/components/chatbar.js +1 -1
- package/dist/esm/components/chatbar.js.map +3 -3
- package/dist/esm/components/icon-button.d.ts.map +1 -1
- package/dist/esm/components/icon-button.js +2 -2
- package/dist/esm/components/icon-button.js.map +3 -3
- package/dist/esm/components/schemas/shell.schema.d.ts +70 -70
- package/dist/esm/components/shell.context.d.ts +1 -0
- package/dist/esm/components/shell.context.d.ts.map +1 -1
- package/dist/esm/components/shell.context.js.map +2 -2
- package/dist/esm/components/shell.d.ts +6 -26
- package/dist/esm/components/shell.d.ts.map +1 -1
- package/dist/esm/components/shell.hooks.d.ts +19 -2
- package/dist/esm/components/shell.hooks.d.ts.map +1 -1
- package/dist/esm/components/shell.hooks.js +1 -1
- package/dist/esm/components/shell.hooks.js.map +3 -3
- package/dist/esm/components/shell.js +1 -1
- package/dist/esm/components/shell.js.map +3 -3
- package/dist/esm/components/shell.types.d.ts +21 -0
- package/dist/esm/components/shell.types.d.ts.map +1 -1
- package/dist/esm/components/shell.types.js.map +2 -2
- package/dist/esm/components/toggle-button.d.ts.map +1 -1
- package/dist/esm/components/toggle-button.js +1 -1
- package/dist/esm/components/toggle-button.js.map +3 -3
- package/dist/esm/components/toggle-icon-button.d.ts.map +1 -1
- package/dist/esm/components/toggle-icon-button.js +1 -1
- package/dist/esm/components/toggle-icon-button.js.map +3 -3
- package/dist/esm/hooks/index.d.ts +2 -0
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/index.js +1 -1
- package/dist/esm/hooks/index.js.map +3 -3
- package/dist/esm/hooks/use-live-announcer.d.ts.map +1 -1
- package/dist/esm/hooks/use-live-announcer.js +2 -2
- package/dist/esm/hooks/use-live-announcer.js.map +3 -3
- package/dist/esm/hooks/use-toggle-state.d.ts +37 -0
- package/dist/esm/hooks/use-toggle-state.d.ts.map +1 -0
- package/dist/esm/hooks/use-toggle-state.js +2 -0
- package/dist/esm/hooks/use-toggle-state.js.map +7 -0
- package/dist/esm/hooks/use-tooltip-wrapper.d.ts +29 -0
- package/dist/esm/hooks/use-tooltip-wrapper.d.ts.map +1 -0
- package/dist/esm/hooks/use-tooltip-wrapper.js +2 -0
- package/dist/esm/hooks/use-tooltip-wrapper.js.map +7 -0
- package/package.json +4 -4
- package/schemas/base-button.json +1 -1
- package/schemas/button.json +1 -1
- package/schemas/icon-button.json +1 -1
- package/schemas/index.json +6 -6
- package/schemas/toggle-button.json +1 -1
- package/schemas/toggle-icon-button.json +1 -1
- package/src/components/_internal/base-button.css +136 -614
- package/src/components/_internal/base-button.tsx +15 -13
- package/src/components/_internal/shell-bottom.tsx +305 -321
- package/src/components/_internal/shell-inspector.tsx +310 -320
- package/src/components/_internal/shell-prop-helpers.ts +53 -0
- package/src/components/_internal/shell-sidebar.tsx +370 -384
- package/src/components/button.tsx +13 -42
- package/src/components/chatbar.tsx +7 -3
- package/src/components/icon-button.tsx +20 -44
- package/src/components/image.css +10 -8
- package/src/components/shell.context.tsx +1 -0
- package/src/components/shell.hooks.ts +67 -2
- package/src/components/shell.tsx +199 -209
- package/src/components/shell.types.ts +23 -0
- package/src/components/toggle-button.tsx +30 -59
- package/src/components/toggle-icon-button.tsx +29 -51
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-live-announcer.ts +34 -7
- package/src/hooks/use-toggle-state.ts +72 -0
- package/src/hooks/use-tooltip-wrapper.ts +28 -0
- package/src/styles/tokens/color.css +11 -1
- package/styles.css +70 -381
- package/tokens/base.css +7 -1
- package/tokens.css +7 -1
|
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
|
|
3
3
|
|
|
4
4
|
import { BaseButton } from './_internal/base-button.js';
|
|
5
5
|
import { Tooltip } from './tooltip.js';
|
|
6
|
+
import { useTooltipWrapper } from '../hooks/use-tooltip-wrapper.js';
|
|
6
7
|
import type { BaseButtonProps } from './_internal/base-button.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -84,9 +85,7 @@ type ButtonProps<C extends React.ElementType = 'button'> = ButtonOwnProps & {
|
|
|
84
85
|
* Button component type that supports polymorphic rendering
|
|
85
86
|
* @template C - The element type to render as
|
|
86
87
|
*/
|
|
87
|
-
type ButtonComponent = <C extends React.ElementType = 'button'>(
|
|
88
|
-
props: ButtonProps<C> & { ref?: React.ForwardedRef<ButtonElement> },
|
|
89
|
-
) => React.ReactElement | null;
|
|
88
|
+
type ButtonComponent = <C extends React.ElementType = 'button'>(props: ButtonProps<C> & { ref?: React.ForwardedRef<ButtonElement> }) => React.ReactElement | null;
|
|
90
89
|
|
|
91
90
|
/**
|
|
92
91
|
* Button component for triggering actions throughout your interface
|
|
@@ -113,27 +112,11 @@ type ButtonComponent = <C extends React.ElementType = 'button'>(
|
|
|
113
112
|
*/
|
|
114
113
|
const Button = React.forwardRef(
|
|
115
114
|
(
|
|
116
|
-
{
|
|
117
|
-
className,
|
|
118
|
-
tooltip,
|
|
119
|
-
tooltipSide = 'top',
|
|
120
|
-
tooltipAlign = 'center',
|
|
121
|
-
tooltipDelayDuration,
|
|
122
|
-
tooltipDisableHoverableContent,
|
|
123
|
-
overrideStyles,
|
|
124
|
-
...props
|
|
125
|
-
}: ButtonProps,
|
|
115
|
+
{ className, style, tooltip, tooltipSide = 'top', tooltipAlign = 'center', tooltipDelayDuration, tooltipDisableHoverableContent, overrideStyles, ...props }: ButtonProps,
|
|
126
116
|
forwardedRef: React.ForwardedRef<ButtonElement>,
|
|
127
117
|
) => {
|
|
128
|
-
//
|
|
129
|
-
const tooltipId =
|
|
130
|
-
const hasTooltip = Boolean(tooltip);
|
|
131
|
-
|
|
132
|
-
// Prepare accessibility props for tooltip integration
|
|
133
|
-
const tooltipAccessibilityProps = React.useMemo(
|
|
134
|
-
() => (hasTooltip ? { 'aria-describedby': tooltipId } : {}),
|
|
135
|
-
[hasTooltip, tooltipId],
|
|
136
|
-
);
|
|
118
|
+
// Use shared tooltip wrapper hook for accessibility props
|
|
119
|
+
const { tooltipId, hasTooltip, accessibilityProps: tooltipAccessibilityProps } = useTooltipWrapper(tooltip);
|
|
137
120
|
|
|
138
121
|
// Create the base button element with tooltip accessibility props
|
|
139
122
|
// Map overrideStyles to CSS variables consumed by the override variant rules
|
|
@@ -152,7 +135,7 @@ const Button = React.forwardRef(
|
|
|
152
135
|
setVar(`--button-override-${prefix}filter`, s.filter);
|
|
153
136
|
setVar(`--button-override-${prefix}outline`, s.outline);
|
|
154
137
|
setVar(`--button-override-${prefix}outline-offset`, s.outlineOffset);
|
|
155
|
-
setVar(`--button-override-${prefix}opacity`, s.opacity
|
|
138
|
+
setVar(`--button-override-${prefix}opacity`, s.opacity);
|
|
156
139
|
};
|
|
157
140
|
|
|
158
141
|
apply('', overrideStyles.normal);
|
|
@@ -167,35 +150,23 @@ const Button = React.forwardRef(
|
|
|
167
150
|
setVar('--button-override-focus-outline-offset', overrideStyles.focus.outlineOffset);
|
|
168
151
|
}
|
|
169
152
|
|
|
170
|
-
return vars as
|
|
153
|
+
return vars as React.CSSProperties;
|
|
171
154
|
}, [overrideStyles]);
|
|
172
155
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
ref={forwardedRef}
|
|
178
|
-
className={classNames('rt-Button', className)}
|
|
179
|
-
style={overrideVars ? { ...overrideVars, ...(props as any).style } : (props as any).style}
|
|
180
|
-
/>
|
|
181
|
-
);
|
|
156
|
+
// Combine override styles with user-provided styles
|
|
157
|
+
const combinedStyle = React.useMemo(() => (overrideVars ? { ...overrideVars, ...style } : style), [overrideVars, style]);
|
|
158
|
+
|
|
159
|
+
const button = <BaseButton {...props} {...tooltipAccessibilityProps} ref={forwardedRef} className={classNames('rt-Button', className)} style={combinedStyle} />;
|
|
182
160
|
|
|
183
161
|
// If no tooltip is provided, return the button as-is for better performance
|
|
184
|
-
if (!
|
|
162
|
+
if (!hasTooltip) {
|
|
185
163
|
return button;
|
|
186
164
|
}
|
|
187
165
|
|
|
188
166
|
// Wrap with Tooltip when tooltip content is provided
|
|
189
167
|
// This creates a compound component that handles both button and tooltip functionality
|
|
190
168
|
return (
|
|
191
|
-
<Tooltip
|
|
192
|
-
content={tooltip}
|
|
193
|
-
side={tooltipSide}
|
|
194
|
-
align={tooltipAlign}
|
|
195
|
-
delayDuration={tooltipDelayDuration}
|
|
196
|
-
disableHoverableContent={tooltipDisableHoverableContent}
|
|
197
|
-
id={tooltipId}
|
|
198
|
-
>
|
|
169
|
+
<Tooltip content={tooltip} side={tooltipSide} align={tooltipAlign} delayDuration={tooltipDelayDuration} disableHoverableContent={tooltipDisableHoverableContent} id={tooltipId}>
|
|
199
170
|
{button}
|
|
200
171
|
</Tooltip>
|
|
201
172
|
);
|
|
@@ -1121,13 +1121,16 @@ const RowEnd = React.forwardRef<HTMLDivElement, React.ComponentPropsWithoutRef<'
|
|
|
1121
1121
|
});
|
|
1122
1122
|
RowEnd.displayName = 'Chatbar.RowEnd';
|
|
1123
1123
|
|
|
1124
|
-
type SendProps = IconButtonProps & {
|
|
1124
|
+
type SendProps = Omit<IconButtonProps, 'aria-label' | 'aria-labelledby'> & {
|
|
1125
|
+
/** Optional override for accessible name. Defaults to "Send". */
|
|
1126
|
+
'aria-label'?: string;
|
|
1127
|
+
'aria-labelledby'?: string;
|
|
1125
1128
|
asChild?: boolean;
|
|
1126
1129
|
clearOnSend?: boolean;
|
|
1127
1130
|
};
|
|
1128
1131
|
|
|
1129
1132
|
const Send = React.forwardRef<HTMLButtonElement, SendProps>((props, forwardedRef) => {
|
|
1130
|
-
const { asChild, clearOnSend = true, disabled, children, className, style, size: sizeProp, variant: variantProp, ...buttonProps } = props;
|
|
1133
|
+
const { asChild, clearOnSend = true, disabled, children, className, style, size: sizeProp, variant: variantProp, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, ...buttonProps } = props;
|
|
1131
1134
|
const ctx = useChatbarContext();
|
|
1132
1135
|
|
|
1133
1136
|
const trimmed = ctx.value.trim();
|
|
@@ -1160,7 +1163,8 @@ const Send = React.forwardRef<HTMLButtonElement, SendProps>((props, forwardedRef
|
|
|
1160
1163
|
}}
|
|
1161
1164
|
asChild={asChild}
|
|
1162
1165
|
onClick={handleClick}
|
|
1163
|
-
aria-label={(
|
|
1166
|
+
aria-label={ariaLabel ?? (ariaLabelledby ? undefined : 'Send')}
|
|
1167
|
+
aria-labelledby={ariaLabelledby}
|
|
1164
1168
|
>
|
|
1165
1169
|
{children ?? (
|
|
1166
1170
|
<svg
|
|
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
|
|
3
3
|
|
|
4
4
|
import { BaseButton } from './_internal/base-button.js';
|
|
5
5
|
import { Tooltip } from './tooltip.js';
|
|
6
|
+
import { useTooltipWrapper } from '../hooks/use-tooltip-wrapper.js';
|
|
6
7
|
import type { BaseButtonProps } from './_internal/base-button.js';
|
|
7
8
|
|
|
8
9
|
type IconButtonElement = React.ElementRef<typeof BaseButton>;
|
|
@@ -57,9 +58,7 @@ type IconButtonProps<C extends React.ElementType = 'button'> = IconButtonOwnProp
|
|
|
57
58
|
* IconButton component type that supports polymorphic rendering
|
|
58
59
|
* @template C - The element type to render as
|
|
59
60
|
*/
|
|
60
|
-
type IconButtonComponent = <C extends React.ElementType = 'button'>(
|
|
61
|
-
props: IconButtonProps<C> & { ref?: React.ForwardedRef<IconButtonElement> },
|
|
62
|
-
) => React.ReactElement | null;
|
|
61
|
+
type IconButtonComponent = <C extends React.ElementType = 'button'>(props: IconButtonProps<C> & { ref?: React.ForwardedRef<IconButtonElement> }) => React.ReactElement | null;
|
|
63
62
|
|
|
64
63
|
/**
|
|
65
64
|
* IconButton component for compact, accessible icon-only interactions
|
|
@@ -103,68 +102,45 @@ type IconButtonComponent = <C extends React.ElementType = 'button'>(
|
|
|
103
102
|
*/
|
|
104
103
|
const IconButton = React.forwardRef(
|
|
105
104
|
(
|
|
106
|
-
{
|
|
107
|
-
className,
|
|
108
|
-
tooltip,
|
|
109
|
-
tooltipSide = 'top',
|
|
110
|
-
tooltipAlign = 'center',
|
|
111
|
-
tooltipDelayDuration,
|
|
112
|
-
tooltipDisableHoverableContent,
|
|
113
|
-
...props
|
|
114
|
-
}: IconButtonProps,
|
|
105
|
+
{ className, tooltip, tooltipSide = 'top', tooltipAlign = 'center', tooltipDelayDuration, tooltipDisableHoverableContent, ...props }: IconButtonProps,
|
|
115
106
|
forwardedRef: React.ForwardedRef<IconButtonElement>,
|
|
116
107
|
) => {
|
|
117
|
-
//
|
|
118
|
-
const tooltipId =
|
|
108
|
+
// Use shared tooltip wrapper hook for accessibility props
|
|
109
|
+
const { tooltipId, hasTooltip, accessibilityProps: tooltipAccessibilityProps } = useTooltipWrapper(tooltip);
|
|
110
|
+
|
|
119
111
|
// Runtime accessibility validation to ensure WCAG compliance
|
|
120
112
|
// This helps catch accessibility issues during development
|
|
121
113
|
const hasAriaLabel = 'aria-label' in props && props['aria-label'];
|
|
122
114
|
const hasAriaLabelledBy = 'aria-labelledby' in props && props['aria-labelledby'];
|
|
123
115
|
const hasChildren = 'children' in props && props.children;
|
|
124
116
|
|
|
125
|
-
//
|
|
117
|
+
// Validate accessible name - throw in development, log error in production
|
|
126
118
|
if (!hasAriaLabel && !hasAriaLabelledBy && !hasChildren) {
|
|
127
|
-
|
|
119
|
+
const errorMessage =
|
|
128
120
|
'IconButton: Icon buttons must have an accessible name. Please provide either:' +
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
);
|
|
133
|
-
}
|
|
121
|
+
'\n- aria-label prop with descriptive text' +
|
|
122
|
+
'\n- aria-labelledby prop referencing a label element' +
|
|
123
|
+
'\n- or visible text children';
|
|
134
124
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
125
|
+
if (process.env.NODE_ENV === 'development') {
|
|
126
|
+
throw new Error(errorMessage);
|
|
127
|
+
} else {
|
|
128
|
+
console.error(errorMessage);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
141
131
|
|
|
142
132
|
// Create the base icon button element with accessibility props
|
|
143
|
-
const iconButton = (
|
|
144
|
-
<BaseButton
|
|
145
|
-
{...props}
|
|
146
|
-
{...tooltipAccessibilityProps}
|
|
147
|
-
ref={forwardedRef}
|
|
148
|
-
className={classNames('rt-IconButton', className)}
|
|
149
|
-
/>
|
|
150
|
-
);
|
|
133
|
+
const iconButton = <BaseButton {...props} {...tooltipAccessibilityProps} ref={forwardedRef} className={classNames('rt-IconButton', className)} />;
|
|
151
134
|
|
|
152
135
|
// If no tooltip is provided, return the icon button as-is for better performance
|
|
153
|
-
if (!
|
|
136
|
+
if (!hasTooltip) {
|
|
154
137
|
return iconButton;
|
|
155
138
|
}
|
|
156
139
|
|
|
157
140
|
// Wrap with Tooltip when tooltip content is provided
|
|
158
141
|
// This creates a compound component that handles both button and tooltip functionality
|
|
159
142
|
return (
|
|
160
|
-
<Tooltip
|
|
161
|
-
content={tooltip}
|
|
162
|
-
side={tooltipSide}
|
|
163
|
-
align={tooltipAlign}
|
|
164
|
-
delayDuration={tooltipDelayDuration}
|
|
165
|
-
disableHoverableContent={tooltipDisableHoverableContent}
|
|
166
|
-
id={tooltipId}
|
|
167
|
-
>
|
|
143
|
+
<Tooltip content={tooltip} side={tooltipSide} align={tooltipAlign} delayDuration={tooltipDelayDuration} disableHoverableContent={tooltipDisableHoverableContent} id={tooltipId}>
|
|
168
144
|
{iconButton}
|
|
169
145
|
</Tooltip>
|
|
170
146
|
);
|
package/src/components/image.css
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
.rt-Image {
|
|
64
64
|
border: 1px solid CanvasText;
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
/* Enhanced focus visibility in forced colors mode */
|
|
68
68
|
.rt-Image:where(:focus-visible) {
|
|
69
69
|
outline: 2px solid Highlight;
|
|
@@ -78,7 +78,9 @@
|
|
|
78
78
|
*/
|
|
79
79
|
.rt-Image:where(:any-link, button, label) {
|
|
80
80
|
cursor: pointer;
|
|
81
|
-
transition:
|
|
81
|
+
transition:
|
|
82
|
+
var(--transition-card),
|
|
83
|
+
filter var(--motion-duration-small) var(--motion-ease-standard); /* Smooth transitions for interactive states */
|
|
82
84
|
|
|
83
85
|
/*
|
|
84
86
|
* Hover effects with progressive enhancement
|
|
@@ -87,7 +89,7 @@
|
|
|
87
89
|
@media (hover: hover) {
|
|
88
90
|
&:where(:hover) {
|
|
89
91
|
box-shadow: var(--shadow-3); /* Subtle elevation on hover */
|
|
90
|
-
filter: brightness(1.
|
|
92
|
+
filter: brightness(1.08) contrast(1.02); /* Slight brightness/contrast boost */
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
|
|
@@ -116,13 +118,15 @@
|
|
|
116
118
|
*/
|
|
117
119
|
:where(:any-link, button, label) {
|
|
118
120
|
cursor: pointer;
|
|
119
|
-
transition:
|
|
121
|
+
transition:
|
|
122
|
+
var(--transition-card),
|
|
123
|
+
filter var(--motion-duration-small) var(--motion-ease-standard); /* Smooth transitions for interactive states */
|
|
120
124
|
|
|
121
125
|
/* Hover effects for wrapper elements */
|
|
122
126
|
@media (hover: hover) {
|
|
123
127
|
&:where(:hover) {
|
|
124
128
|
/* box-shadow: var(--shadow-3); */
|
|
125
|
-
filter: brightness(1.
|
|
129
|
+
filter: brightness(1.08) contrast(1.02);
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
132
|
|
|
@@ -141,8 +145,6 @@
|
|
|
141
145
|
outline-offset: -2px;
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
|
|
145
|
-
|
|
146
148
|
/*
|
|
147
149
|
* Object-fit variants for responsive image scaling
|
|
148
150
|
* These classes control how images are resized to fit their containers
|
|
@@ -217,7 +219,7 @@
|
|
|
217
219
|
color: var(--gray-11); /* Subtle but readable color */
|
|
218
220
|
margin-top: var(--space-2); /* Consistent spacing from image */
|
|
219
221
|
text-align: center; /* Centered alignment for visual balance */
|
|
220
|
-
|
|
222
|
+
|
|
221
223
|
/*
|
|
222
224
|
* Text wrapping and hyphenation for better layout
|
|
223
225
|
* Prevents caption text from breaking the layout
|
|
@@ -45,6 +45,7 @@ export interface ShellContextValue {
|
|
|
45
45
|
|
|
46
46
|
const ShellContext = React.createContext<ShellContextValue | null>(null);
|
|
47
47
|
|
|
48
|
+
/** @internal Shell root context. Prefer slice hooks (useSidebarMode, useShellActions, etc.). */
|
|
48
49
|
export function useShell() {
|
|
49
50
|
const ctx = React.useContext(ShellContext);
|
|
50
51
|
if (!ctx) throw new Error('Shell components must be used within <Shell.Root>');
|
|
@@ -3,7 +3,7 @@ import type { Breakpoint, PresentationValue, ResponsivePresentation } from './sh
|
|
|
3
3
|
import { _BREAKPOINTS } from './shell.types.js';
|
|
4
4
|
import { useShell } from './shell.context.js';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
function useResponsivePresentation(presentation: ResponsivePresentation): PresentationValue {
|
|
7
7
|
const { currentBreakpoint } = useShell();
|
|
8
8
|
|
|
9
9
|
return React.useMemo(() => {
|
|
@@ -35,7 +35,7 @@ export function useResponsivePresentation(presentation: ResponsivePresentation):
|
|
|
35
35
|
* If no value is defined for the current breakpoint, search smaller breakpoints down to 'initial'.
|
|
36
36
|
* Returns undefined when passed a responsive map with no matching key across the chain.
|
|
37
37
|
*/
|
|
38
|
-
|
|
38
|
+
function useResponsiveValue<T>(value: T | Partial<Record<Breakpoint, T>> | undefined): T | undefined {
|
|
39
39
|
const { currentBreakpoint } = useShell();
|
|
40
40
|
|
|
41
41
|
return React.useMemo(() => {
|
|
@@ -64,3 +64,68 @@ export function useResponsiveValue<T>(value: T | Partial<Record<Breakpoint, T>>
|
|
|
64
64
|
return undefined;
|
|
65
65
|
}, [value, currentBreakpoint]);
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
type ResponsiveStateValue<T> = T | Partial<Record<Breakpoint, T>>;
|
|
69
|
+
|
|
70
|
+
interface UseResponsiveInitialStateOptions<T> {
|
|
71
|
+
controlledValue?: ResponsiveStateValue<T>;
|
|
72
|
+
defaultValue?: ResponsiveStateValue<T>;
|
|
73
|
+
currentValue: T;
|
|
74
|
+
setValue: (value: T) => void;
|
|
75
|
+
breakpointReady: boolean;
|
|
76
|
+
onInit?: (value: T) => void;
|
|
77
|
+
onResponsiveChange?: (value: T) => void;
|
|
78
|
+
controlledIsResponsive?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface UseResponsiveInitialStateResult<T> {
|
|
82
|
+
resolvedControlled?: T;
|
|
83
|
+
resolvedDefault?: T;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function useResponsiveInitialState<T>({
|
|
87
|
+
controlledValue,
|
|
88
|
+
defaultValue,
|
|
89
|
+
currentValue,
|
|
90
|
+
setValue,
|
|
91
|
+
breakpointReady,
|
|
92
|
+
onInit,
|
|
93
|
+
onResponsiveChange,
|
|
94
|
+
controlledIsResponsive = false,
|
|
95
|
+
}: UseResponsiveInitialStateOptions<T>): UseResponsiveInitialStateResult<T> {
|
|
96
|
+
const resolvedControlled = useResponsiveValue(controlledValue);
|
|
97
|
+
const resolvedDefault = useResponsiveValue(defaultValue);
|
|
98
|
+
|
|
99
|
+
const lastControlledRef = React.useRef<T | undefined>(undefined);
|
|
100
|
+
React.useEffect(() => {
|
|
101
|
+
if (resolvedControlled === undefined) return;
|
|
102
|
+
lastControlledRef.current = resolvedControlled;
|
|
103
|
+
if (currentValue === resolvedControlled) {
|
|
104
|
+
if (controlledIsResponsive) {
|
|
105
|
+
onResponsiveChange?.(resolvedControlled);
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
setValue(resolvedControlled);
|
|
110
|
+
if (controlledIsResponsive) {
|
|
111
|
+
onResponsiveChange?.(resolvedControlled);
|
|
112
|
+
}
|
|
113
|
+
}, [resolvedControlled, currentValue, setValue, onResponsiveChange, controlledIsResponsive]);
|
|
114
|
+
|
|
115
|
+
const didInitRef = React.useRef(false);
|
|
116
|
+
React.useEffect(() => {
|
|
117
|
+
if (didInitRef.current) return;
|
|
118
|
+
if (!breakpointReady) return;
|
|
119
|
+
if (typeof controlledValue !== 'undefined') return;
|
|
120
|
+
if (resolvedDefault === undefined) return;
|
|
121
|
+
didInitRef.current = true;
|
|
122
|
+
if (currentValue !== resolvedDefault) {
|
|
123
|
+
setValue(resolvedDefault);
|
|
124
|
+
}
|
|
125
|
+
onInit?.(resolvedDefault);
|
|
126
|
+
}, [breakpointReady, controlledValue, resolvedDefault, currentValue, setValue, onInit]);
|
|
127
|
+
|
|
128
|
+
return { resolvedControlled, resolvedDefault };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { useResponsivePresentation, useResponsiveValue, useResponsiveInitialState };
|