ionbase-ui 0.11.0 → 0.13.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/dist/components/Alert.d.ts +44 -0
- package/dist/components/Alert.d.ts.map +1 -0
- package/dist/components/Alert.js +56 -0
- package/dist/components/Alert.js.map +1 -0
- package/dist/components/Tooltip.d.ts +49 -0
- package/dist/components/Tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip.js +51 -0
- package/dist/components/Tooltip.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/styles/alert.css +241 -0
- package/dist/styles/index.css +2 -0
- package/dist/styles/tooltip.css +118 -0
- package/package.json +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type AlertIntent = 'neutral' | 'primary' | 'success' | 'warning' | 'error' | 'information';
|
|
3
|
+
export type AlertEmphasis = 'subtle' | 'solid';
|
|
4
|
+
export type AlertLayout = 'inline' | 'banner';
|
|
5
|
+
export interface AlertProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
6
|
+
/** Matches the Figma `Intent` variant. Same vocabulary as `Badge`. */
|
|
7
|
+
intent?: AlertIntent;
|
|
8
|
+
/** Matches the Figma `Emphasis` variant. */
|
|
9
|
+
emphasis?: AlertEmphasis;
|
|
10
|
+
/** Matches the Figma `Layout` variant. */
|
|
11
|
+
layout?: AlertLayout;
|
|
12
|
+
/** Optional heading above the message. */
|
|
13
|
+
title?: React.ReactNode;
|
|
14
|
+
/** Hide the leading icon. Shown by default. */
|
|
15
|
+
hideIcon?: boolean;
|
|
16
|
+
/** Replace the intent's glyph. */
|
|
17
|
+
icon?: React.ReactNode;
|
|
18
|
+
/** Action buttons, rendered under the message. */
|
|
19
|
+
actions?: React.ReactNode;
|
|
20
|
+
/** Called when the dismiss button is pressed. Omit for no dismiss button. */
|
|
21
|
+
onDismiss?: () => void;
|
|
22
|
+
/** Accessible name for the dismiss button. */
|
|
23
|
+
dismissLabel?: string;
|
|
24
|
+
/** The message. */
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Alert — Figma `Alert` (812:1902).
|
|
29
|
+
*
|
|
30
|
+
* `Intent` x `Emphasis` x `Layout`, with the parts as props rather than
|
|
31
|
+
* variants. Intents match `Badge` exactly, so a status mapped to one can be
|
|
32
|
+
* passed to the other.
|
|
33
|
+
*
|
|
34
|
+
* ROLE IS CHOSEN BY INTENT, NOT PASSED IN. `error` and `warning` render
|
|
35
|
+
* `role="alert"`, which interrupts a screen reader; the rest render
|
|
36
|
+
* `role="status"`, which waits for a pause. Getting this backwards is the
|
|
37
|
+
* common failure — a page of `role="alert"` status messages talks over the
|
|
38
|
+
* user, and an error announced as a status is missed.
|
|
39
|
+
*
|
|
40
|
+
* The icon is decorative: it repeats what the intent's colour and copy already
|
|
41
|
+
* say, so it is `aria-hidden` and the live region carries the text alone.
|
|
42
|
+
*/
|
|
43
|
+
export declare const Alert: React.ForwardRefExoticComponent<AlertProps & React.RefAttributes<HTMLDivElement>>;
|
|
44
|
+
//# sourceMappingURL=Alert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../src/components/Alert.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,WAAW,GACrB,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAC1E,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC/C,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAuF9C,MAAM,WAAW,UAAW,SAAQ,IAAI,CACtC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,OAAO,CACR;IACC,sEAAsE;IACtE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kCAAkC;IAClC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,kDAAkD;IAClD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,KAAK,mFA0DhB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* The per-intent glyphs, inlined for the same reason Select's and Modal's are:
|
|
5
|
+
* they belong to the component rather than to a slot a caller fills, and
|
|
6
|
+
* `ionbase-ui` deliberately does not depend on `ionbase-icons`.
|
|
7
|
+
*
|
|
8
|
+
* One per intent, not one shared symbol. A success alert showing an info circle
|
|
9
|
+
* is wrong rather than merely unstyled — which is exactly what happened in
|
|
10
|
+
* Figma when the icon was bound to a single instance-swap default.
|
|
11
|
+
*/
|
|
12
|
+
const Info = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "M12 16v-4M12 8h.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] }));
|
|
13
|
+
const CircleCheck = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "m9 12 2 2 4-4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
14
|
+
const TriangleAlert = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("path", { d: "M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M12 9v4M12 17h.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] }));
|
|
15
|
+
const CircleX = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "m15 9-6 6M9 9l6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] }));
|
|
16
|
+
const DismissIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M18 6 6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
17
|
+
const INTENT_ICON = {
|
|
18
|
+
neutral: Info,
|
|
19
|
+
primary: Info,
|
|
20
|
+
information: Info,
|
|
21
|
+
success: CircleCheck,
|
|
22
|
+
warning: TriangleAlert,
|
|
23
|
+
error: CircleX,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Alert — Figma `Alert` (812:1902).
|
|
27
|
+
*
|
|
28
|
+
* `Intent` x `Emphasis` x `Layout`, with the parts as props rather than
|
|
29
|
+
* variants. Intents match `Badge` exactly, so a status mapped to one can be
|
|
30
|
+
* passed to the other.
|
|
31
|
+
*
|
|
32
|
+
* ROLE IS CHOSEN BY INTENT, NOT PASSED IN. `error` and `warning` render
|
|
33
|
+
* `role="alert"`, which interrupts a screen reader; the rest render
|
|
34
|
+
* `role="status"`, which waits for a pause. Getting this backwards is the
|
|
35
|
+
* common failure — a page of `role="alert"` status messages talks over the
|
|
36
|
+
* user, and an error announced as a status is missed.
|
|
37
|
+
*
|
|
38
|
+
* The icon is decorative: it repeats what the intent's colour and copy already
|
|
39
|
+
* say, so it is `aria-hidden` and the live region carries the text alone.
|
|
40
|
+
*/
|
|
41
|
+
export const Alert = forwardRef((props, ref) => {
|
|
42
|
+
const { intent = 'information', emphasis = 'subtle', layout = 'inline', title, hideIcon, icon, actions, onDismiss, dismissLabel = 'Dismiss', className, children, ...rest } = props;
|
|
43
|
+
const IntentIcon = INTENT_ICON[intent];
|
|
44
|
+
const isUrgent = intent === 'error' || intent === 'warning';
|
|
45
|
+
return (_jsxs("div", { ...rest, ref: ref, role: isUrgent ? 'alert' : 'status', className: [
|
|
46
|
+
'ion-alert',
|
|
47
|
+
`ion-alert--${intent}`,
|
|
48
|
+
`ion-alert--${emphasis}`,
|
|
49
|
+
`ion-alert--${layout}`,
|
|
50
|
+
className || '',
|
|
51
|
+
]
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
.join(' '), children: [!hideIcon && (_jsx("span", { className: "ion-alert__icon", "aria-hidden": "true", children: icon ?? _jsx(IntentIcon, {}) })), _jsxs("div", { className: "ion-alert__content", children: [title && _jsx("p", { className: "ion-alert__title", children: title }), children && _jsx("div", { className: "ion-alert__message", children: children }), actions && _jsx("div", { className: "ion-alert__actions", children: actions })] }), onDismiss && (_jsx("button", { type: "button", className: "ion-alert__dismiss", onClick: onDismiss, "aria-label": dismissLabel, children: _jsx(DismissIcon, {}) }))] }));
|
|
54
|
+
});
|
|
55
|
+
Alert.displayName = 'Alert';
|
|
56
|
+
//# sourceMappingURL=Alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../src/components/Alert.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
3
|
+
export interface TooltipProps {
|
|
4
|
+
/**
|
|
5
|
+
* The hint. A tooltip is text only — anything interactive or focusable
|
|
6
|
+
* belongs in a popover, because a tooltip cannot be focused, cannot be
|
|
7
|
+
* scrolled, and closes the moment the pointer leaves.
|
|
8
|
+
*/
|
|
9
|
+
label: React.ReactNode;
|
|
10
|
+
/** Optional heading above the label. */
|
|
11
|
+
title?: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Matches the Figma `Placement` variant, and names where the TOOLTIP sits —
|
|
14
|
+
* not where the arrow points. `top` is above the trigger, with the arrow on
|
|
15
|
+
* the tooltip's bottom edge.
|
|
16
|
+
*
|
|
17
|
+
* Treated as a preference, not a guarantee: it flips to the opposite side
|
|
18
|
+
* when there is no room, which is the behaviour Figma cannot draw.
|
|
19
|
+
*/
|
|
20
|
+
placement?: TooltipPlacement;
|
|
21
|
+
/** Milliseconds before it opens on hover. Focus always opens immediately. */
|
|
22
|
+
delay?: number;
|
|
23
|
+
/** Disable the tooltip without unmounting the trigger. */
|
|
24
|
+
isDisabled?: boolean;
|
|
25
|
+
/** The element the tooltip describes. Must accept a ref and DOM props. */
|
|
26
|
+
children: React.ReactElement;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Tooltip — Figma `Tooltip` (801:1568).
|
|
31
|
+
*
|
|
32
|
+
* Wraps its trigger rather than taking a ref, so the common case is one
|
|
33
|
+
* element deep: `<Tooltip label="..."><Button/></Tooltip>`.
|
|
34
|
+
*
|
|
35
|
+
* FOCUS OPENS IT, NOT JUST HOVER. A hover-only tooltip is invisible to keyboard
|
|
36
|
+
* and switch users, and `useTooltipTrigger` wires both plus Escape to dismiss.
|
|
37
|
+
* It also enforces one open tooltip at a time and a shared warmup, so moving
|
|
38
|
+
* along a row of icon buttons does not flash a tooltip per button.
|
|
39
|
+
*
|
|
40
|
+
* The trigger is cloned with the interaction props and a ref, which means it
|
|
41
|
+
* must forward both. Every component in this library does; a bare `<div>` does
|
|
42
|
+
* too. A function component that drops its ref will render, but the tooltip
|
|
43
|
+
* will have nothing to position against.
|
|
44
|
+
*/
|
|
45
|
+
export declare function Tooltip({ label, title, placement, delay, isDisabled, children, className, }: TooltipProps): React.JSX.Element;
|
|
46
|
+
export declare namespace Tooltip {
|
|
47
|
+
var displayName: string;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../src/components/Tooltip.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAWpD,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnE,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,SAAiB,EACjB,KAAW,EACX,UAAU,EACV,QAAQ,EACR,SAAS,GACV,EAAE,YAAY,qBAmEd;yBA3Ee,OAAO"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { cloneElement, useRef } from 'react';
|
|
4
|
+
import { Overlay, useTooltip, useTooltipTrigger, useOverlayPosition, mergeProps, } from 'react-aria';
|
|
5
|
+
import { useTooltipTriggerState } from 'react-stately';
|
|
6
|
+
/**
|
|
7
|
+
* Tooltip — Figma `Tooltip` (801:1568).
|
|
8
|
+
*
|
|
9
|
+
* Wraps its trigger rather than taking a ref, so the common case is one
|
|
10
|
+
* element deep: `<Tooltip label="..."><Button/></Tooltip>`.
|
|
11
|
+
*
|
|
12
|
+
* FOCUS OPENS IT, NOT JUST HOVER. A hover-only tooltip is invisible to keyboard
|
|
13
|
+
* and switch users, and `useTooltipTrigger` wires both plus Escape to dismiss.
|
|
14
|
+
* It also enforces one open tooltip at a time and a shared warmup, so moving
|
|
15
|
+
* along a row of icon buttons does not flash a tooltip per button.
|
|
16
|
+
*
|
|
17
|
+
* The trigger is cloned with the interaction props and a ref, which means it
|
|
18
|
+
* must forward both. Every component in this library does; a bare `<div>` does
|
|
19
|
+
* too. A function component that drops its ref will render, but the tooltip
|
|
20
|
+
* will have nothing to position against.
|
|
21
|
+
*/
|
|
22
|
+
export function Tooltip({ label, title, placement = 'top', delay = 400, isDisabled, children, className, }) {
|
|
23
|
+
const state = useTooltipTriggerState({ delay, isDisabled });
|
|
24
|
+
const triggerRef = useRef(null);
|
|
25
|
+
const overlayRef = useRef(null);
|
|
26
|
+
const { triggerProps, tooltipProps } = useTooltipTrigger({ isDisabled }, state, triggerRef);
|
|
27
|
+
const { tooltipProps: ariaTooltipProps } = useTooltip(tooltipProps, state);
|
|
28
|
+
/*
|
|
29
|
+
* `offset` is the gap between trigger and bubble, and it has to clear the
|
|
30
|
+
* arrow or the caret sits on top of the thing it points at. 4px arrow plus
|
|
31
|
+
* a 4px gap.
|
|
32
|
+
*/
|
|
33
|
+
const { overlayProps, arrowProps, placement: resolvedPlacement, } = useOverlayPosition({
|
|
34
|
+
targetRef: triggerRef,
|
|
35
|
+
overlayRef,
|
|
36
|
+
placement: placement,
|
|
37
|
+
offset: 8,
|
|
38
|
+
isOpen: state.isOpen,
|
|
39
|
+
});
|
|
40
|
+
// `resolvedPlacement` rather than the prop: react-aria flips on collision,
|
|
41
|
+
// and the arrow has to move with it or it points at nothing.
|
|
42
|
+
const side = (resolvedPlacement ?? placement).split(' ')[0];
|
|
43
|
+
return (_jsxs(_Fragment, { children: [cloneElement(children, mergeProps(children.props, {
|
|
44
|
+
...triggerProps,
|
|
45
|
+
ref: triggerRef,
|
|
46
|
+
})), state.isOpen && (_jsx(Overlay, { children: _jsxs("div", { ...mergeProps(ariaTooltipProps, overlayProps), ref: overlayRef, className: ['ion-tooltip', `ion-tooltip--${side}`, className || '']
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.join(' '), children: [_jsxs("div", { className: "ion-tooltip__bubble", children: [title && _jsx("div", { className: "ion-tooltip__title", children: title }), _jsx("div", { className: "ion-tooltip__label", children: label })] }), _jsx("div", { ...arrowProps, className: "ion-tooltip__arrow", "aria-hidden": "true" })] }) }))] }));
|
|
49
|
+
}
|
|
50
|
+
Tooltip.displayName = 'Tooltip';
|
|
51
|
+
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../src/components/Tooltip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAc,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EACL,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAgCvD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,OAAO,CAAC,EACtB,KAAK,EACL,KAAK,EACL,SAAS,GAAG,KAAK,EACjB,KAAK,GAAG,GAAG,EACX,UAAU,EACV,QAAQ,EACR,SAAS,GACI;IACb,MAAM,KAAK,GAAG,sBAAsB,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAG,MAAM,CAAc,IAAI,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEhD,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,iBAAiB,CACtD,EAAE,UAAU,EAAE,EACd,KAAK,EACL,UAAU,CACX,CAAC;IACF,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAE3E;;;;OAIG;IACH,MAAM,EACJ,YAAY,EACZ,UAAU,EACV,SAAS,EAAE,iBAAiB,GAC7B,GAAG,kBAAkB,CAAC;QACrB,SAAS,EAAE,UAAU;QACrB,UAAU;QACV,SAAS,EAAE,SAAsB;QACjC,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;IAEH,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAM,IAAI,GAAG,CAAC,iBAAiB,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5D,OAAO,CACL,8BACG,YAAY,CACX,QAAQ,EACR,UAAU,CAAC,QAAQ,CAAC,KAAgC,EAAE;gBACpD,GAAG,YAAY;gBACf,GAAG,EAAE,UAAU;aAChB,CAAC,CACH,EACA,KAAK,CAAC,MAAM,IAAI,CACf,KAAC,OAAO,cACN,kBACM,UAAU,CAAC,gBAAgB,EAAE,YAAY,CAAC,EAC9C,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,CAAC,aAAa,EAAE,gBAAgB,IAAI,EAAE,EAAE,SAAS,IAAI,EAAE,CAAC;yBAChE,MAAM,CAAC,OAAO,CAAC;yBACf,IAAI,CAAC,GAAG,CAAC,aAEZ,eAAK,SAAS,EAAC,qBAAqB,aACjC,KAAK,IAAI,cAAK,SAAS,EAAC,oBAAoB,YAAE,KAAK,GAAO,EAC3D,cAAK,SAAS,EAAC,oBAAoB,YAAE,KAAK,GAAO,IAC7C,EACN,iBACM,UAAU,EACd,SAAS,EAAC,oBAAoB,iBAGlB,MAAM,GAClB,IACE,GACE,CACX,IACA,CACJ,CAAC;AACJ,CAAC;AAED,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC"}
|
|
@@ -2,6 +2,8 @@ export { Button } from './Button.js';
|
|
|
2
2
|
export type { ButtonProps } from './Button.js';
|
|
3
3
|
export { Tabs, TabItem } from './Tabs.js';
|
|
4
4
|
export type { TabsProps, TabsType, TabsSize } from './Tabs.js';
|
|
5
|
+
export { Alert } from './Alert.js';
|
|
6
|
+
export type { AlertProps, AlertIntent, AlertEmphasis, AlertLayout, } from './Alert.js';
|
|
5
7
|
export { Badge } from './Badge.js';
|
|
6
8
|
export type { BadgeProps, BadgeIntent } from './Badge.js';
|
|
7
9
|
export { Input } from './Input.js';
|
|
@@ -26,6 +28,8 @@ export { Logo, LogoMark } from './Logo.js';
|
|
|
26
28
|
export type { LogoProps, LogoMarkProps, LogoSize, LogoWordmark, } from './Logo.js';
|
|
27
29
|
export { Divider } from './Divider.js';
|
|
28
30
|
export type { DividerProps, DividerOrientation } from './Divider.js';
|
|
31
|
+
export { Tooltip } from './Tooltip.js';
|
|
32
|
+
export type { TooltipProps, TooltipPlacement } from './Tooltip.js';
|
|
29
33
|
export { Modal } from './Modal.js';
|
|
30
34
|
export type { ModalProps, ModalSize, ModalAlign } from './Modal.js';
|
|
31
35
|
export { Link } from './Link.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
package/dist/components/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { Button } from './Button.js';
|
|
2
2
|
export { Tabs, TabItem } from './Tabs.js';
|
|
3
|
+
export { Alert } from './Alert.js';
|
|
3
4
|
export { Badge } from './Badge.js';
|
|
4
5
|
export { Input } from './Input.js';
|
|
5
6
|
export { PhoneInput } from './PhoneInput.js';
|
|
@@ -12,6 +13,7 @@ export { Avatar, AvatarGroup } from './Avatar.js';
|
|
|
12
13
|
export { Header } from './Header.js';
|
|
13
14
|
export { Logo, LogoMark } from './Logo.js';
|
|
14
15
|
export { Divider } from './Divider.js';
|
|
16
|
+
export { Tooltip } from './Tooltip.js';
|
|
15
17
|
export { Modal } from './Modal.js';
|
|
16
18
|
export { Link } from './Link.js';
|
|
17
19
|
export { NavItem } from './NavItem.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMzC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAO3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU9E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAOnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMzC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAO3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU9E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Alert
|
|
3
|
+
*
|
|
4
|
+
* Measured from Figma `Alert` (812:1902). Intent x Emphasis x Layout.
|
|
5
|
+
*
|
|
6
|
+
* INTENT IS A SET OF SLOTS, NOT A RULE PER PROPERTY
|
|
7
|
+
*
|
|
8
|
+
* Six intents times two emphases is twelve colour combinations. Reassigning
|
|
9
|
+
* four variables per combination keeps the structural rules — padding, gap,
|
|
10
|
+
* radius, the icon box — written once, and means adding an intent is four
|
|
11
|
+
* lines rather than a new copy of the whole component.
|
|
12
|
+
*
|
|
13
|
+
* The intents match Badge exactly: `surface/<intent>-subtle`,
|
|
14
|
+
* `border/<intent>-subtle`, `text/<intent>`, `icon/<intent>`, with neutral on
|
|
15
|
+
* `surface/muted`. A status mapped to a Badge intent can be passed here.
|
|
16
|
+
*/
|
|
17
|
+
.ion-alert {
|
|
18
|
+
--ion-alert-surface: var(--surface-information-subtle);
|
|
19
|
+
--ion-alert-border: var(--border-information-subtle);
|
|
20
|
+
--ion-alert-text: var(--text-information);
|
|
21
|
+
--ion-alert-icon: var(--icon-information);
|
|
22
|
+
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: flex-start;
|
|
25
|
+
gap: var(--spacing-12);
|
|
26
|
+
padding: var(--spacing-16);
|
|
27
|
+
background-color: var(--ion-alert-surface);
|
|
28
|
+
border: var(--border-width-default) solid var(--ion-alert-border);
|
|
29
|
+
border-radius: var(--radius-md);
|
|
30
|
+
color: var(--ion-alert-text);
|
|
31
|
+
font-family: var(--font-family-sans);
|
|
32
|
+
font-size: var(--type-body);
|
|
33
|
+
line-height: var(--type-body-line-height);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* --- Intent, subtle tier --- */
|
|
37
|
+
.ion-alert--neutral {
|
|
38
|
+
--ion-alert-surface: var(--surface-muted);
|
|
39
|
+
--ion-alert-border: var(--border-default);
|
|
40
|
+
--ion-alert-text: var(--text-secondary);
|
|
41
|
+
--ion-alert-icon: var(--icon-secondary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.ion-alert--primary {
|
|
45
|
+
--ion-alert-surface: var(--surface-primary-subtle);
|
|
46
|
+
--ion-alert-border: var(--border-primary-subtle);
|
|
47
|
+
--ion-alert-text: var(--text-link);
|
|
48
|
+
--ion-alert-icon: var(--icon-primary);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ion-alert--success {
|
|
52
|
+
--ion-alert-surface: var(--surface-success-subtle);
|
|
53
|
+
--ion-alert-border: var(--border-success-subtle);
|
|
54
|
+
--ion-alert-text: var(--text-success);
|
|
55
|
+
--ion-alert-icon: var(--icon-success);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.ion-alert--warning {
|
|
59
|
+
--ion-alert-surface: var(--surface-warning-subtle);
|
|
60
|
+
--ion-alert-border: var(--border-warning-subtle);
|
|
61
|
+
--ion-alert-text: var(--text-warning);
|
|
62
|
+
--ion-alert-icon: var(--icon-warning);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.ion-alert--error {
|
|
66
|
+
--ion-alert-surface: var(--surface-error-subtle);
|
|
67
|
+
--ion-alert-border: var(--border-error-subtle);
|
|
68
|
+
--ion-alert-text: var(--text-error);
|
|
69
|
+
--ion-alert-icon: var(--icon-error);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.ion-alert--information {
|
|
73
|
+
--ion-alert-surface: var(--surface-information-subtle);
|
|
74
|
+
--ion-alert-border: var(--border-information-subtle);
|
|
75
|
+
--ion-alert-text: var(--text-information);
|
|
76
|
+
--ion-alert-icon: var(--icon-information);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* --- Solid tier ---
|
|
81
|
+
*
|
|
82
|
+
* The accent surface at full strength under `text/on-color`, the same pairing
|
|
83
|
+
* Button's solid variants use. Written after the intents so it wins on order
|
|
84
|
+
* at equal specificity, and only the surface and border differ per intent —
|
|
85
|
+
* the text and icon are the same two roles throughout.
|
|
86
|
+
*
|
|
87
|
+
* KNOWN, pending a decision on the accent ramps: solid `success` measures
|
|
88
|
+
* 3.69:1 in Light and solid `information` 3.44:1 in Dark against
|
|
89
|
+
* `text/on-color`, both short of WCAG AA's 4.5:1 for normal text. Neither is a
|
|
90
|
+
* one-step fix — every accent runs base/hover/pressed at 600/700/800, so
|
|
91
|
+
* moving a base onto 700 makes it identical to its own hover. See AGENTS.md.
|
|
92
|
+
*/
|
|
93
|
+
.ion-alert--solid {
|
|
94
|
+
--ion-alert-text: var(--text-on-color);
|
|
95
|
+
--ion-alert-icon: var(--icon-on-color);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.ion-alert--solid.ion-alert--neutral {
|
|
99
|
+
--ion-alert-surface: var(--surface-inverse);
|
|
100
|
+
--ion-alert-border: var(--border-inverse);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.ion-alert--solid.ion-alert--primary {
|
|
104
|
+
--ion-alert-surface: var(--surface-primary);
|
|
105
|
+
--ion-alert-border: var(--border-primary-strong);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.ion-alert--solid.ion-alert--success {
|
|
109
|
+
--ion-alert-surface: var(--surface-success);
|
|
110
|
+
--ion-alert-border: var(--border-success-strong);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ion-alert--solid.ion-alert--warning {
|
|
114
|
+
--ion-alert-surface: var(--surface-warning);
|
|
115
|
+
--ion-alert-border: var(--border-warning-strong);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ion-alert--solid.ion-alert--error {
|
|
119
|
+
--ion-alert-surface: var(--surface-error);
|
|
120
|
+
--ion-alert-border: var(--border-error-strong);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ion-alert--solid.ion-alert--information {
|
|
124
|
+
--ion-alert-surface: var(--surface-information);
|
|
125
|
+
--ion-alert-border: var(--border-information-strong);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/*
|
|
129
|
+
* --- Banner ---
|
|
130
|
+
*
|
|
131
|
+
* A banner meets its container's edges, so the radius goes and the SIDE
|
|
132
|
+
* borders go with it: a 1px rule at the viewport edge is invisible on one side
|
|
133
|
+
* and reads as a seam on the other. The block edges keep theirs, which is what
|
|
134
|
+
* separates a subtle banner from the page behind it.
|
|
135
|
+
*/
|
|
136
|
+
.ion-alert--banner {
|
|
137
|
+
border-radius: 0;
|
|
138
|
+
border-inline: none;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* --- Parts --- */
|
|
142
|
+
.ion-alert__icon {
|
|
143
|
+
display: inline-flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
flex-shrink: 0;
|
|
147
|
+
color: var(--ion-alert-icon);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* Sized to the icon ladder rather than to `1em`, unlike Link's. A Link
|
|
152
|
+
* inherits its type from the sentence around it; an Alert sets its own, so the
|
|
153
|
+
* icon has a fixed rung to sit on.
|
|
154
|
+
*
|
|
155
|
+
* The line-height box is what it centres against: `--type-body-line-height` is
|
|
156
|
+
* 24 and the icon is 20, so the 2px above and below line the glyph up with the
|
|
157
|
+
* first line of text rather than with the top of the box.
|
|
158
|
+
*/
|
|
159
|
+
.ion-alert__icon svg {
|
|
160
|
+
width: var(--icon-size-md);
|
|
161
|
+
height: var(--icon-size-md);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.ion-alert__icon,
|
|
165
|
+
.ion-alert__dismiss {
|
|
166
|
+
min-height: var(--type-body-line-height);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.ion-alert__content {
|
|
170
|
+
display: flex;
|
|
171
|
+
flex: 1 1 auto;
|
|
172
|
+
min-width: 0;
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
gap: var(--spacing-8);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ion-alert__title {
|
|
178
|
+
margin: 0;
|
|
179
|
+
font-weight: var(--font-weight-medium);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.ion-alert__message {
|
|
183
|
+
margin: 0;
|
|
184
|
+
font-weight: var(--font-weight-regular);
|
|
185
|
+
|
|
186
|
+
/* Long tokens — a URL, an id — must wrap rather than widen the alert. */
|
|
187
|
+
overflow-wrap: anywhere;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.ion-alert__actions {
|
|
191
|
+
display: flex;
|
|
192
|
+
align-items: center;
|
|
193
|
+
gap: var(--spacing-8);
|
|
194
|
+
flex-wrap: wrap;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/*
|
|
198
|
+
* The dismiss target is 32px around a 20px glyph. WCAG 2.2 SC 2.5.8 asks for
|
|
199
|
+
* 24x24 minimum and the icon alone would fail it — the same reasoning as
|
|
200
|
+
* Modal's close. Do not shrink it to fit the icon.
|
|
201
|
+
*/
|
|
202
|
+
.ion-alert__dismiss {
|
|
203
|
+
display: inline-flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
justify-content: center;
|
|
206
|
+
flex-shrink: 0;
|
|
207
|
+
width: var(--spacing-32);
|
|
208
|
+
height: var(--spacing-32);
|
|
209
|
+
padding: 0;
|
|
210
|
+
background: none;
|
|
211
|
+
border: none;
|
|
212
|
+
border-radius: var(--radius-sm);
|
|
213
|
+
color: var(--ion-alert-icon);
|
|
214
|
+
cursor: pointer;
|
|
215
|
+
transition: background-color var(--ion-duration-base) var(--ion-ease-out);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.ion-alert__dismiss svg {
|
|
219
|
+
width: var(--icon-size-md);
|
|
220
|
+
height: var(--icon-size-md);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@media (hover: hover) {
|
|
224
|
+
.ion-alert__dismiss:hover {
|
|
225
|
+
background-color: var(--surface-hover);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.ion-alert__dismiss:focus-visible {
|
|
230
|
+
outline: var(--border-width-thick) solid var(--ring-focus);
|
|
231
|
+
outline-offset: 2px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/*
|
|
235
|
+
* On a solid surface the focus ring has to come from the text colour, not the
|
|
236
|
+
* brand ring — `ring/focus` is a mid-blue that all but disappears against a
|
|
237
|
+
* solid primary or information surface.
|
|
238
|
+
*/
|
|
239
|
+
.ion-alert--solid .ion-alert__dismiss:focus-visible {
|
|
240
|
+
outline-color: var(--text-on-color);
|
|
241
|
+
}
|
package/dist/styles/index.css
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
@import url('./icon.css');
|
|
30
30
|
@import url('./button.css');
|
|
31
31
|
@import url('./tabs.css');
|
|
32
|
+
@import url('./alert.css');
|
|
32
33
|
@import url('./badge.css');
|
|
33
34
|
@import url('./input.css');
|
|
34
35
|
@import url('./phone-input.css');
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
@import url('./divider.css');
|
|
45
46
|
@import url('./link.css');
|
|
46
47
|
@import url('./modal.css');
|
|
48
|
+
@import url('./tooltip.css');
|
|
47
49
|
@import url('./nav-item.css');
|
|
48
50
|
@import url('./scroll-progress.css');
|
|
49
51
|
@import url('./full-card.css');
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tooltip
|
|
3
|
+
*
|
|
4
|
+
* Measured from Figma `Tooltip` (801:1568). Four placements.
|
|
5
|
+
*
|
|
6
|
+
* THE INVERSE TRIO
|
|
7
|
+
*
|
|
8
|
+
* `surface/inverse` with `text/inverse` on it — the only pairing in the system
|
|
9
|
+
* that inverts as a unit, so the tooltip is dark on a light theme and light on
|
|
10
|
+
* a dark one with no second variant and no `@media` of its own. Both were
|
|
11
|
+
* defined long before anything used them; this is `text/inverse`'s first
|
|
12
|
+
* consumer anywhere.
|
|
13
|
+
*/
|
|
14
|
+
.ion-tooltip {
|
|
15
|
+
position: absolute;
|
|
16
|
+
z-index: 1100;
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Above the modal's 1000. A tooltip on a control inside a dialog is the
|
|
20
|
+
* ordinary case — a trigger in a modal footer, say — and at a lower z-index
|
|
21
|
+
* it would render behind the panel it belongs to.
|
|
22
|
+
*/
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* The bubble carries the surface; the arrow is a sibling.
|
|
30
|
+
*
|
|
31
|
+
* Drawing the arrow as a rotated pseudo-element ON the bubble is the usual
|
|
32
|
+
* shortcut and it fights the shadow: a rotated square inherits the box-shadow
|
|
33
|
+
* and casts a second, offset one. Keeping them separate means the arrow can
|
|
34
|
+
* take the same fill without the same shadow.
|
|
35
|
+
*/
|
|
36
|
+
.ion-tooltip__bubble {
|
|
37
|
+
/*
|
|
38
|
+
* A hint, not a container. Long enough for a sentence, short enough that it
|
|
39
|
+
* never becomes a paragraph — anything that needs more belongs in a popover.
|
|
40
|
+
*/
|
|
41
|
+
max-width: 280px;
|
|
42
|
+
padding: var(--spacing-8) var(--spacing-12);
|
|
43
|
+
background-color: var(--surface-inverse);
|
|
44
|
+
border-radius: var(--radius-sm);
|
|
45
|
+
box-shadow: var(--ion-shadow-shadow-md);
|
|
46
|
+
color: var(--text-inverse);
|
|
47
|
+
font-family: var(--font-family-sans);
|
|
48
|
+
font-size: var(--type-body-sm);
|
|
49
|
+
line-height: var(--type-body-sm-line-height);
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* Wrap long hints rather than forcing the overlay wider than the viewport.
|
|
53
|
+
* `overflow-wrap` catches the single-long-token case that `max-width` alone
|
|
54
|
+
* cannot.
|
|
55
|
+
*/
|
|
56
|
+
overflow-wrap: anywhere;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ion-tooltip__title {
|
|
60
|
+
margin-bottom: var(--spacing-4);
|
|
61
|
+
font-weight: var(--font-weight-medium);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ion-tooltip__label {
|
|
65
|
+
font-weight: var(--font-weight-regular);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* The arrow, as a triangle from borders rather than a rotated box.
|
|
70
|
+
*
|
|
71
|
+
* A rotated square would need its own shadow suppression and would round its
|
|
72
|
+
* corners with the bubble's radius. Border triangles have neither problem, and
|
|
73
|
+
* the transparent sides collapse to nothing.
|
|
74
|
+
*
|
|
75
|
+
* `--ion-tooltip-arrow` is the visible length; the base is twice that, which
|
|
76
|
+
* is what makes the caret 8 wide and 4 deep at the default.
|
|
77
|
+
*/
|
|
78
|
+
.ion-tooltip__arrow {
|
|
79
|
+
--ion-tooltip-arrow: var(--spacing-4);
|
|
80
|
+
|
|
81
|
+
position: absolute;
|
|
82
|
+
width: 0;
|
|
83
|
+
height: 0;
|
|
84
|
+
border: var(--ion-tooltip-arrow) solid transparent;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
* Placement names where the TOOLTIP sits, so the arrow is always on the
|
|
89
|
+
* opposite edge — `--top` puts the caret underneath, pointing down at the
|
|
90
|
+
* trigger below it.
|
|
91
|
+
*
|
|
92
|
+
* These follow react-aria's RESOLVED placement, not the requested one. It
|
|
93
|
+
* flips on collision, and an arrow left on the requested side would point away
|
|
94
|
+
* from the trigger entirely.
|
|
95
|
+
*/
|
|
96
|
+
.ion-tooltip--top .ion-tooltip__arrow {
|
|
97
|
+
bottom: calc(-2 * var(--ion-tooltip-arrow));
|
|
98
|
+
border-top-color: var(--surface-inverse);
|
|
99
|
+
border-bottom-width: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ion-tooltip--bottom .ion-tooltip__arrow {
|
|
103
|
+
top: calc(-2 * var(--ion-tooltip-arrow));
|
|
104
|
+
border-bottom-color: var(--surface-inverse);
|
|
105
|
+
border-top-width: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.ion-tooltip--left .ion-tooltip__arrow {
|
|
109
|
+
right: calc(-2 * var(--ion-tooltip-arrow));
|
|
110
|
+
border-left-color: var(--surface-inverse);
|
|
111
|
+
border-right-width: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.ion-tooltip--right .ion-tooltip__arrow {
|
|
115
|
+
left: calc(-2 * var(--ion-tooltip-arrow));
|
|
116
|
+
border-right-color: var(--surface-inverse);
|
|
117
|
+
border-left-width: 0;
|
|
118
|
+
}
|