kang-components 0.6.0 → 0.9.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/badge.d.ts +34 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +46 -0
- package/dist/badge.js.map +1 -0
- package/dist/bottom-sheet.d.ts +60 -0
- package/dist/bottom-sheet.d.ts.map +1 -0
- package/dist/bottom-sheet.js +201 -0
- package/dist/bottom-sheet.js.map +1 -0
- package/dist/confirm-dialog.d.ts +40 -0
- package/dist/confirm-dialog.d.ts.map +1 -0
- package/dist/confirm-dialog.js +74 -0
- package/dist/confirm-dialog.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/list-item.d.ts +74 -0
- package/dist/list-item.d.ts.map +1 -0
- package/dist/list-item.js +105 -0
- package/dist/list-item.js.map +1 -0
- package/dist/list-item.styles.d.ts +55 -0
- package/dist/list-item.styles.d.ts.map +1 -0
- package/dist/list-item.styles.js +151 -0
- package/dist/list-item.styles.js.map +1 -0
- package/dist/toggle-switch.d.ts +38 -0
- package/dist/toggle-switch.d.ts.map +1 -0
- package/dist/toggle-switch.js +118 -0
- package/dist/toggle-switch.js.map +1 -0
- package/dist/use-viewport-size.d.ts +16 -0
- package/dist/use-viewport-size.d.ts.map +1 -0
- package/dist/use-viewport-size.js +38 -0
- package/dist/use-viewport-size.js.map +1 -0
- package/package.json +6 -1
package/dist/badge.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge — a domain-free pill that displays a prominent value with an optional
|
|
3
|
+
* label, in one of a few visual variants.
|
|
4
|
+
*
|
|
5
|
+
* Ported from ymy-components (`./badge/Badge`), where it lived as a 3-file unit
|
|
6
|
+
* (`Badge.tsx` + `Badge.types.ts` + `Badge.styles.ts`) and shipped untested.
|
|
7
|
+
* The kang port collapses it into a single flat-ESM module and preserves the
|
|
8
|
+
* public API exactly (`value`, `label`, `variant`), so xunzi's re-point site
|
|
9
|
+
* (`StreakBadge.tsx`) is a pure import swap.
|
|
10
|
+
*
|
|
11
|
+
* Theming follows kang conventions: every color reads a styled-components
|
|
12
|
+
* `theme.colors.*` token with a literal fallback, so the badge adapts to a
|
|
13
|
+
* `ThemeProvider` (light/dark) yet still renders sensibly without one. The ymy
|
|
14
|
+
* source hardcoded the `success` variant's green; the kang port routes it
|
|
15
|
+
* through the theme's `successContainer`/`successDark` tokens (same literal
|
|
16
|
+
* fallbacks) so it matches mode like every other variant.
|
|
17
|
+
*
|
|
18
|
+
* `styled-components` and `react` are the only things this module pulls in.
|
|
19
|
+
*/
|
|
20
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
21
|
+
export type BadgeVariant = 'primary' | 'muted' | 'success';
|
|
22
|
+
export interface BadgeProps {
|
|
23
|
+
/** The primary value displayed prominently. */
|
|
24
|
+
value: ReactNode;
|
|
25
|
+
/** Optional label displayed next to the value (rendered uppercase). */
|
|
26
|
+
label?: string;
|
|
27
|
+
/** Visual variant (default: `'primary'`). */
|
|
28
|
+
variant?: BadgeVariant;
|
|
29
|
+
/** Optional class name passthrough for layout/positioning by the consumer. */
|
|
30
|
+
className?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function Badge({ value, label, variant, className, }: BadgeProps): ReactElement;
|
|
33
|
+
export default Badge;
|
|
34
|
+
//# sourceMappingURL=badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../src/badge.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG1D,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3D,MAAM,WAAW,UAAU;IAC1B,+CAA+C;IAC/C,KAAK,EAAE,SAAS,CAAC;IACjB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAiDD,wBAAgB,KAAK,CAAC,EACrB,KAAK,EACL,KAAK,EACL,OAAmB,EACnB,SAAS,GACT,EAAE,UAAU,GAAG,YAAY,CAO3B;AAED,eAAe,KAAK,CAAC"}
|
package/dist/badge.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { styled, css } from 'styled-components';
|
|
3
|
+
const containerVariant = {
|
|
4
|
+
primary: css `
|
|
5
|
+
background: ${({ theme }) => theme?.colors?.whiteLow ?? 'rgba(255, 255, 255, 0.2)'};
|
|
6
|
+
`,
|
|
7
|
+
muted: css `
|
|
8
|
+
background: ${({ theme }) => theme?.colors?.surfaceVariant ?? 'rgba(0, 0, 0, 0.06)'};
|
|
9
|
+
`,
|
|
10
|
+
success: css `
|
|
11
|
+
background: ${({ theme }) => theme?.colors?.successContainer ?? 'rgba(34, 197, 94, 0.15)'};
|
|
12
|
+
`,
|
|
13
|
+
};
|
|
14
|
+
const BadgeContainer = styled.div `
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
gap: 0.25rem;
|
|
19
|
+
padding: 0.75rem 1rem;
|
|
20
|
+
border-radius: 1rem;
|
|
21
|
+
min-width: 4rem;
|
|
22
|
+
${({ $variant }) => containerVariant[$variant]}
|
|
23
|
+
`;
|
|
24
|
+
const BadgeValue = styled.span `
|
|
25
|
+
font-size: 1.25rem;
|
|
26
|
+
font-weight: 600;
|
|
27
|
+
line-height: 1;
|
|
28
|
+
color: ${({ $variant, theme }) => {
|
|
29
|
+
const colors = theme?.colors;
|
|
30
|
+
if ($variant === 'success')
|
|
31
|
+
return colors?.successDark ?? '#16a34a';
|
|
32
|
+
return colors?.primaryDarker ?? colors?.primary ?? '#333';
|
|
33
|
+
}};
|
|
34
|
+
`;
|
|
35
|
+
const BadgeLabel = styled.span `
|
|
36
|
+
font-size: 0.625rem;
|
|
37
|
+
font-weight: 500;
|
|
38
|
+
color: ${({ theme }) => theme?.colors?.onSurface ?? '#333'};
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
letter-spacing: 0.05em;
|
|
41
|
+
`;
|
|
42
|
+
export function Badge({ value, label, variant = 'primary', className, }) {
|
|
43
|
+
return (_jsxs(BadgeContainer, { "$variant": variant, className: className, children: [_jsx(BadgeValue, { "$variant": variant, children: value }), label && _jsx(BadgeLabel, { children: label })] }));
|
|
44
|
+
}
|
|
45
|
+
export default Badge;
|
|
46
|
+
//# sourceMappingURL=badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.js","sourceRoot":"","sources":["../src/badge.tsx"],"names":[],"mappings":";AAqBA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAiBhD,MAAM,gBAAgB,GAAG;IACxB,OAAO,EAAE,GAAG,CAAA;gBACG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAC1B,KAAqB,EAAE,MAAM,EAAE,QAAQ,IAAI,0BAA0B;EACvE;IACD,KAAK,EAAE,GAAG,CAAA;gBACK,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAC1B,KAAqB,EAAE,MAAM,EAAE,cAAc,IAAI,qBAAqB;EACxE;IACD,OAAO,EAAE,GAAG,CAAA;gBACG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAC1B,KAAqB,EAAE,MAAM,EAAE,gBAAgB,IAAI,yBAAyB;EAC9E;CACD,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAA4B;;;;;;;;GAQ1D,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC;CAC9C,CAAC;AAEF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAA4B;;;;UAIhD,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;IAChC,MAAM,MAAM,GAAI,KAAqB,EAAE,MAAM,CAAC;IAC9C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,MAAM,EAAE,WAAW,IAAI,SAAS,CAAC;IACpE,OAAO,MAAM,EAAE,aAAa,IAAI,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC;AAC3D,CAAC;CACD,CAAC;AAEF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAA;;;UAGpB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAE,KAAqB,EAAE,MAAM,EAAE,SAAS,IAAI,MAAM;;;CAG3E,CAAC;AAEF,MAAM,UAAU,KAAK,CAAC,EACrB,KAAK,EACL,KAAK,EACL,OAAO,GAAG,SAAS,EACnB,SAAS,GACG;IACZ,OAAO,CACN,MAAC,cAAc,gBAAW,OAAO,EAAE,SAAS,EAAE,SAAS,aACtD,KAAC,UAAU,gBAAW,OAAO,YAAG,KAAK,GAAc,EAClD,KAAK,IAAI,KAAC,UAAU,cAAE,KAAK,GAAc,IAC1B,CACjB,CAAC;AACH,CAAC;AAED,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BottomSheet — a draggable bottom-sheet modal with gesture support.
|
|
3
|
+
*
|
|
4
|
+
* Ported faithfully from ymy-components (`./bottom-sheet/BottomSheet`). The public
|
|
5
|
+
* API (`BottomSheetProps`) is preserved 1:1 so xunzi's single re-point site
|
|
6
|
+
* (`src/views/bottom-sheet/BottomSheet.tsx`, imported as `LibraryBottomSheet`) is a
|
|
7
|
+
* pure import swap.
|
|
8
|
+
*
|
|
9
|
+
* Behavior: an overlay + a panel that slides up from the bottom. The handle area
|
|
10
|
+
* is draggable (rubber-band physics dragging up, velocity- or distance-based
|
|
11
|
+
* swipe-to-close dragging down). Clicking the overlay or swiping past the close
|
|
12
|
+
* threshold calls `onClose`. The component owns a `shouldRender` flag so it can
|
|
13
|
+
* play the slide-out animation before unmounting, and fires `onExitComplete` once
|
|
14
|
+
* the close actually finishes (an interrupted close — reopened mid-animation —
|
|
15
|
+
* does NOT unmount or fire the callback).
|
|
16
|
+
*
|
|
17
|
+
* ⚠️ onExitComplete / onClose stability (the historically fragile part):
|
|
18
|
+
* ymy listed `onExitComplete` in the deps of the effect driving the open/close
|
|
19
|
+
* spring, so a consumer passing a fresh inline callback every render re-ran that
|
|
20
|
+
* effect on every parent re-render — snapping the sheet off-screen then back
|
|
21
|
+
* (jitter), and, when several landed in a row, leaving it off-screen long enough
|
|
22
|
+
* to look like it self-closed (xunzi worked around this by forcing a stable
|
|
23
|
+
* `useCallback`). Kang removes that footgun: the latest `onExitComplete` and
|
|
24
|
+
* `onClose` are stashed in refs and read from the spring's `onRest` / drag-release
|
|
25
|
+
* handler, so a new callback identity NEVER re-kicks the open/close spring. The
|
|
26
|
+
* open/close effect depends ONLY on `isOpen` (+ `maxHeight`/`api`), which are the
|
|
27
|
+
* things that should actually drive it. See the regression test.
|
|
28
|
+
*
|
|
29
|
+
* Theming: surface / scrim / outline / radius / padding read off styled-components'
|
|
30
|
+
* `props.theme` tokens (assembled by kang's `buildTheme`), with the same literal
|
|
31
|
+
* fallbacks ymy shipped so it renders sensibly with or without a `ThemeProvider`.
|
|
32
|
+
* `styled-components`, `@react-spring/web` and `@use-gesture/react` are optional
|
|
33
|
+
* peer dependencies, used only by this module.
|
|
34
|
+
*/
|
|
35
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
36
|
+
export interface BottomSheetProps {
|
|
37
|
+
/** Whether the sheet is open */
|
|
38
|
+
isOpen: boolean;
|
|
39
|
+
/** Callback when the sheet should close */
|
|
40
|
+
onClose: () => void;
|
|
41
|
+
/** Content to render inside the sheet */
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
/** Accessible title for screen readers */
|
|
44
|
+
title?: string;
|
|
45
|
+
/** Max height of the sheet (default: 300) */
|
|
46
|
+
maxHeight?: number;
|
|
47
|
+
/** Velocity threshold for swipe-to-close in px/ms (default: 0.4) */
|
|
48
|
+
velocityThreshold?: number;
|
|
49
|
+
/** Percentage of height drag required to close (default: 0.25) */
|
|
50
|
+
closeThreshold?: number;
|
|
51
|
+
/** Fires after the close animation finishes (use for cleanup like clearing content) */
|
|
52
|
+
onExitComplete?: () => void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Draggable bottom sheet modal with gesture support.
|
|
56
|
+
* Features rubber-band physics, velocity-based swipe detection, and smooth animations.
|
|
57
|
+
*/
|
|
58
|
+
export declare function BottomSheet({ isOpen, onClose, children, title, maxHeight, velocityThreshold, closeThreshold, onExitComplete, }: BottomSheetProps): ReactElement;
|
|
59
|
+
export default BottomSheet;
|
|
60
|
+
//# sourceMappingURL=bottom-sheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bottom-sheet.d.ts","sourceRoot":"","sources":["../src/bottom-sheet.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,SAAS,EAKd,MAAM,OAAO,CAAC;AAQf,MAAM,WAAW,gBAAgB;IAChC,gCAAgC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yCAAyC;IACzC,QAAQ,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAkED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAC3B,MAAM,EACN,OAAO,EACP,QAAQ,EACR,KAAsB,EACtB,SAAe,EACf,iBAAuB,EACvB,cAAqB,EACrB,cAAc,GACd,EAAE,gBAAgB,GAAG,YAAY,CAkJjC;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* BottomSheet — a draggable bottom-sheet modal with gesture support.
|
|
4
|
+
*
|
|
5
|
+
* Ported faithfully from ymy-components (`./bottom-sheet/BottomSheet`). The public
|
|
6
|
+
* API (`BottomSheetProps`) is preserved 1:1 so xunzi's single re-point site
|
|
7
|
+
* (`src/views/bottom-sheet/BottomSheet.tsx`, imported as `LibraryBottomSheet`) is a
|
|
8
|
+
* pure import swap.
|
|
9
|
+
*
|
|
10
|
+
* Behavior: an overlay + a panel that slides up from the bottom. The handle area
|
|
11
|
+
* is draggable (rubber-band physics dragging up, velocity- or distance-based
|
|
12
|
+
* swipe-to-close dragging down). Clicking the overlay or swiping past the close
|
|
13
|
+
* threshold calls `onClose`. The component owns a `shouldRender` flag so it can
|
|
14
|
+
* play the slide-out animation before unmounting, and fires `onExitComplete` once
|
|
15
|
+
* the close actually finishes (an interrupted close — reopened mid-animation —
|
|
16
|
+
* does NOT unmount or fire the callback).
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ onExitComplete / onClose stability (the historically fragile part):
|
|
19
|
+
* ymy listed `onExitComplete` in the deps of the effect driving the open/close
|
|
20
|
+
* spring, so a consumer passing a fresh inline callback every render re-ran that
|
|
21
|
+
* effect on every parent re-render — snapping the sheet off-screen then back
|
|
22
|
+
* (jitter), and, when several landed in a row, leaving it off-screen long enough
|
|
23
|
+
* to look like it self-closed (xunzi worked around this by forcing a stable
|
|
24
|
+
* `useCallback`). Kang removes that footgun: the latest `onExitComplete` and
|
|
25
|
+
* `onClose` are stashed in refs and read from the spring's `onRest` / drag-release
|
|
26
|
+
* handler, so a new callback identity NEVER re-kicks the open/close spring. The
|
|
27
|
+
* open/close effect depends ONLY on `isOpen` (+ `maxHeight`/`api`), which are the
|
|
28
|
+
* things that should actually drive it. See the regression test.
|
|
29
|
+
*
|
|
30
|
+
* Theming: surface / scrim / outline / radius / padding read off styled-components'
|
|
31
|
+
* `props.theme` tokens (assembled by kang's `buildTheme`), with the same literal
|
|
32
|
+
* fallbacks ymy shipped so it renders sensibly with or without a `ThemeProvider`.
|
|
33
|
+
* `styled-components`, `@react-spring/web` and `@use-gesture/react` are optional
|
|
34
|
+
* peer dependencies, used only by this module.
|
|
35
|
+
*/
|
|
36
|
+
import { useRef, useEffect, useCallback, useState, } from 'react';
|
|
37
|
+
import { useSpring, animated } from '@react-spring/web';
|
|
38
|
+
import { useDrag } from '@use-gesture/react';
|
|
39
|
+
// Named import (not the default) so styled-components resolves consistently
|
|
40
|
+
// across bundler and raw ESM/CJS environments — matches the other styled
|
|
41
|
+
// kang primitives (ripple.ts, toggle-switch.tsx).
|
|
42
|
+
import { styled } from 'styled-components';
|
|
43
|
+
const colors = (theme) => theme?.colors ?? {};
|
|
44
|
+
const styling = (theme) => theme?.styling ?? {};
|
|
45
|
+
const spacing = (theme) => theme?.spacing ?? {};
|
|
46
|
+
const SheetOverlay = styled.div `
|
|
47
|
+
position: absolute;
|
|
48
|
+
inset: 0;
|
|
49
|
+
background-color: ${({ theme }) => colors(theme).scrim ?? 'rgba(0, 0, 0, 0.4)'};
|
|
50
|
+
`;
|
|
51
|
+
const SheetContent = styled.div `
|
|
52
|
+
background-color: rgb(${({ theme }) => colors(theme).surfaceRgb ?? '255, 255, 255'});
|
|
53
|
+
border-top-left-radius: ${({ theme }) => styling(theme).borderRadiusPixel ?? 24}px;
|
|
54
|
+
border-top-right-radius: ${({ theme }) => styling(theme).borderRadiusPixel ?? 24}px;
|
|
55
|
+
max-height: 85dvh;
|
|
56
|
+
padding-bottom: max(env(safe-area-inset-bottom), 16px);
|
|
57
|
+
`;
|
|
58
|
+
const SheetHandle = styled.div `
|
|
59
|
+
width: 40px;
|
|
60
|
+
height: 5px;
|
|
61
|
+
background-color: ${({ theme }) => colors(theme).outline ?? 'rgba(0, 0, 0, 0.3)'};
|
|
62
|
+
border-radius: 3px;
|
|
63
|
+
margin: 12px auto 8px;
|
|
64
|
+
`;
|
|
65
|
+
const SheetBody = styled.div `
|
|
66
|
+
padding: 0 ${({ theme }) => spacing(theme).appStandardPadding ?? '16px'};
|
|
67
|
+
`;
|
|
68
|
+
const VisuallyHidden = styled.span `
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: 1px;
|
|
71
|
+
height: 1px;
|
|
72
|
+
padding: 0;
|
|
73
|
+
margin: -1px;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
clip: rect(0, 0, 0, 0);
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
border: 0;
|
|
78
|
+
`;
|
|
79
|
+
// Rubber-band damping function (from Vaul)
|
|
80
|
+
function dampenValue(v) {
|
|
81
|
+
return 8 * (Math.log(v + 1) - 2);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Draggable bottom sheet modal with gesture support.
|
|
85
|
+
* Features rubber-band physics, velocity-based swipe detection, and smooth animations.
|
|
86
|
+
*/
|
|
87
|
+
export function BottomSheet({ isOpen, onClose, children, title = 'Bottom Sheet', maxHeight = 300, velocityThreshold = 0.4, closeThreshold = 0.25, onExitComplete, }) {
|
|
88
|
+
const modalRef = useRef(null);
|
|
89
|
+
const [shouldRender, setShouldRender] = useState(isOpen);
|
|
90
|
+
// Mirror of shouldRender for the effect to read the latest value without
|
|
91
|
+
// re-subscribing (adding shouldRender to the effect deps would re-run
|
|
92
|
+
// open/close on every toggle and reintroduce the snap).
|
|
93
|
+
const shouldRenderRef = useRef(shouldRender);
|
|
94
|
+
shouldRenderRef.current = shouldRender;
|
|
95
|
+
// Stash the latest callbacks in refs so the open/close spring effect never
|
|
96
|
+
// depends on their identity. A consumer passing a fresh inline onExitComplete
|
|
97
|
+
// (or onClose) every render must NOT re-kick the open/close spring — that was
|
|
98
|
+
// the jitter / apparent-self-close bug. The effect reads .current at the
|
|
99
|
+
// moment it actually needs the callback (on close-finished / on drag-release).
|
|
100
|
+
const onExitCompleteRef = useRef(onExitComplete);
|
|
101
|
+
onExitCompleteRef.current = onExitComplete;
|
|
102
|
+
const onCloseRef = useRef(onClose);
|
|
103
|
+
onCloseRef.current = onClose;
|
|
104
|
+
const [spring, api] = useSpring(() => ({
|
|
105
|
+
y: maxHeight,
|
|
106
|
+
opacity: 0,
|
|
107
|
+
config: { tension: 300, friction: 30 },
|
|
108
|
+
}));
|
|
109
|
+
// Handle open/close. Deps are intentionally ONLY [isOpen, api, maxHeight]:
|
|
110
|
+
// the callbacks are read from refs so their identity can't re-run this effect.
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (isOpen) {
|
|
113
|
+
const openDistance = modalRef.current?.offsetHeight || maxHeight;
|
|
114
|
+
// Only hard-snap to the closed position when opening from fully
|
|
115
|
+
// closed. When reopening mid-close (a sheet swap), reverse from the
|
|
116
|
+
// current position instead of jumping to the bottom.
|
|
117
|
+
if (!shouldRenderRef.current) {
|
|
118
|
+
api.set({ y: openDistance, opacity: 0 });
|
|
119
|
+
}
|
|
120
|
+
setShouldRender(true);
|
|
121
|
+
api.start({ y: 0, opacity: 1 });
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const closeDistance = modalRef.current?.offsetHeight || maxHeight;
|
|
125
|
+
api.start({
|
|
126
|
+
y: closeDistance,
|
|
127
|
+
opacity: 0,
|
|
128
|
+
onRest: (result) => {
|
|
129
|
+
// Only tear down when the close actually finished. An
|
|
130
|
+
// interrupted close (reopened mid-animation) fires onRest
|
|
131
|
+
// with finished:false and must NOT unmount the sheet.
|
|
132
|
+
if (result?.finished) {
|
|
133
|
+
setShouldRender(false);
|
|
134
|
+
onExitCompleteRef.current?.();
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}, [isOpen, api, maxHeight]);
|
|
140
|
+
const handleClose = useCallback(() => {
|
|
141
|
+
onCloseRef.current();
|
|
142
|
+
}, []);
|
|
143
|
+
// Drag handler
|
|
144
|
+
const bind = useDrag(({ active, movement: [, my], velocity: [, vy], direction: [, dy], cancel }) => {
|
|
145
|
+
// Prevent dragging up beyond the top
|
|
146
|
+
if (my < -10) {
|
|
147
|
+
cancel();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const dragDistance = Math.max(0, my);
|
|
151
|
+
if (active) {
|
|
152
|
+
// Apply rubber-band effect when dragging up
|
|
153
|
+
const dampened = my < 0 ? dampenValue(-my) * -0.5 : dragDistance;
|
|
154
|
+
api.start({ y: dampened, immediate: true });
|
|
155
|
+
// Fade overlay based on drag progress
|
|
156
|
+
const progress = Math.min(dragDistance / maxHeight, 1);
|
|
157
|
+
api.start({ opacity: 1 - progress * 0.5, immediate: true });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Check if should close based on velocity or distance
|
|
161
|
+
const shouldClose = (vy > velocityThreshold && dy > 0) ||
|
|
162
|
+
dragDistance > maxHeight * closeThreshold;
|
|
163
|
+
if (shouldClose) {
|
|
164
|
+
handleClose();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
api.start({ y: 0, opacity: 1 });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}, {
|
|
171
|
+
from: () => [0, spring.y.get()],
|
|
172
|
+
filterTaps: true,
|
|
173
|
+
axis: 'y',
|
|
174
|
+
pointer: { touch: true },
|
|
175
|
+
preventDefault: true,
|
|
176
|
+
eventOptions: { passive: false },
|
|
177
|
+
});
|
|
178
|
+
if (!shouldRender) {
|
|
179
|
+
return _jsx(_Fragment, {});
|
|
180
|
+
}
|
|
181
|
+
return (_jsxs(_Fragment, { children: [_jsx(animated.div, { style: {
|
|
182
|
+
position: 'fixed',
|
|
183
|
+
inset: 0,
|
|
184
|
+
zIndex: 49,
|
|
185
|
+
opacity: spring.opacity,
|
|
186
|
+
pointerEvents: isOpen ? 'auto' : 'none',
|
|
187
|
+
}, onClick: handleClose, children: _jsx(SheetOverlay, {}) }), _jsx(animated.div, { style: {
|
|
188
|
+
position: 'fixed',
|
|
189
|
+
bottom: 0,
|
|
190
|
+
left: 0,
|
|
191
|
+
right: 0,
|
|
192
|
+
zIndex: 50,
|
|
193
|
+
transform: spring.y.to((y) => `translateY(${y}px)`),
|
|
194
|
+
}, children: _jsxs(SheetContent, { ref: modalRef, children: [_jsx(VisuallyHidden, { children: title }), _jsx("div", { ...bind(), style: {
|
|
195
|
+
touchAction: 'none',
|
|
196
|
+
cursor: 'grab',
|
|
197
|
+
padding: '8px 0',
|
|
198
|
+
}, children: _jsx(SheetHandle, {}) }), _jsx(SheetBody, { children: children })] }) })] }));
|
|
199
|
+
}
|
|
200
|
+
export default BottomSheet;
|
|
201
|
+
//# sourceMappingURL=bottom-sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bottom-sheet.js","sourceRoot":"","sources":["../src/bottom-sheet.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmDialog — a domain-free confirm/cancel prompt: a centered message, an
|
|
3
|
+
* optional description, and stacked confirm + cancel buttons with Material-style
|
|
4
|
+
* ripple press feedback. The confirm button can be marked `destructive` for a
|
|
5
|
+
* red-tinted danger action.
|
|
6
|
+
*
|
|
7
|
+
* Ported from ymy-components (`./confirm-dialog/ConfirmDialog`), where it lived
|
|
8
|
+
* as a 3-file unit (`ConfirmDialog.tsx` + `.types.ts` + `.styles.ts`) and
|
|
9
|
+
* shipped untested. The kang port collapses it into a single flat-ESM module and
|
|
10
|
+
* preserves the public API exactly (`message`, `description`, `confirmLabel`,
|
|
11
|
+
* `cancelLabel`, `destructive`, `onConfirm`, `onCancel`), so xunzi's two
|
|
12
|
+
* re-point sites (`ClearDataConfirm.tsx`, `LogoutConfirm.tsx`) are pure import
|
|
13
|
+
* swaps.
|
|
14
|
+
*
|
|
15
|
+
* Theming follows kang conventions: the destructive button reads the theme's
|
|
16
|
+
* `error` token (with the ymy literal `#dc2626` / `rgba(220, 38, 38, 0.1)` as
|
|
17
|
+
* fallbacks) so it adapts to a `ThemeProvider` (light/dark) yet still renders
|
|
18
|
+
* sensibly without one. Ripple feedback reuses kang's `useRipple` / `Ripple`
|
|
19
|
+
* primitives. `styled-components` and `react` are the only runtime imports.
|
|
20
|
+
*/
|
|
21
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
22
|
+
export interface ConfirmDialogProps {
|
|
23
|
+
/** Primary message displayed at the top. */
|
|
24
|
+
message: ReactNode;
|
|
25
|
+
/** Optional secondary description below the message. */
|
|
26
|
+
description?: ReactNode;
|
|
27
|
+
/** Label for the confirm button. */
|
|
28
|
+
confirmLabel: ReactNode;
|
|
29
|
+
/** Label for the cancel button. */
|
|
30
|
+
cancelLabel: ReactNode;
|
|
31
|
+
/** Whether the confirm action is destructive (red-tinted button). */
|
|
32
|
+
destructive?: boolean;
|
|
33
|
+
/** Callback when confirm is clicked. */
|
|
34
|
+
onConfirm: () => void;
|
|
35
|
+
/** Callback when cancel is clicked. */
|
|
36
|
+
onCancel: () => void;
|
|
37
|
+
}
|
|
38
|
+
export declare function ConfirmDialog({ message, description, confirmLabel, cancelLabel, destructive, onConfirm, onCancel, }: ConfirmDialogProps): ReactElement;
|
|
39
|
+
export default ConfirmDialog;
|
|
40
|
+
//# sourceMappingURL=confirm-dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-dialog.d.ts","sourceRoot":"","sources":["../src/confirm-dialog.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IAClC,4CAA4C;IAC5C,OAAO,EAAE,SAAS,CAAC;IACnB,wDAAwD;IACxD,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,oCAAoC;IACpC,YAAY,EAAE,SAAS,CAAC;IACxB,mCAAmC;IACnC,WAAW,EAAE,SAAS,CAAC;IACvB,qEAAqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wCAAwC;IACxC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACrB;AA8DD,wBAAgB,aAAa,CAAC,EAC7B,OAAO,EACP,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAmB,EACnB,SAAS,EACT,QAAQ,GACR,EAAE,kBAAkB,GAAG,YAAY,CA+BnC;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { styled } from 'styled-components';
|
|
3
|
+
import { Ripple, useRipple } from './ripple.js';
|
|
4
|
+
/** Convert a hex color (`#rrggbb`) to an `r, g, b` triple for rgba() usage. */
|
|
5
|
+
function hexToRgbTriple(hex) {
|
|
6
|
+
const h = hex.replace('#', '');
|
|
7
|
+
if (h.length !== 6)
|
|
8
|
+
return null;
|
|
9
|
+
const r = parseInt(h.slice(0, 2), 16);
|
|
10
|
+
const g = parseInt(h.slice(2, 4), 16);
|
|
11
|
+
const b = parseInt(h.slice(4, 6), 16);
|
|
12
|
+
if ([r, g, b].some((n) => Number.isNaN(n)))
|
|
13
|
+
return null;
|
|
14
|
+
return `${r}, ${g}, ${b}`;
|
|
15
|
+
}
|
|
16
|
+
const DialogContainer = styled.div `
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
gap: 0.5rem;
|
|
20
|
+
`;
|
|
21
|
+
const DialogMessage = styled.div `
|
|
22
|
+
text-align: center;
|
|
23
|
+
padding: 0.5rem 1rem;
|
|
24
|
+
font-weight: 300;
|
|
25
|
+
`;
|
|
26
|
+
const DialogDescription = styled.div `
|
|
27
|
+
text-align: center;
|
|
28
|
+
padding: 0 1rem 1rem;
|
|
29
|
+
font-size: 0.875rem;
|
|
30
|
+
opacity: 0.7;
|
|
31
|
+
`;
|
|
32
|
+
const DialogButton = styled.button `
|
|
33
|
+
position: relative;
|
|
34
|
+
z-index: 1;
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
padding: 1rem;
|
|
39
|
+
font-family: inherit;
|
|
40
|
+
font-size: 1.125rem;
|
|
41
|
+
font-weight: 300;
|
|
42
|
+
border: none;
|
|
43
|
+
border-radius: 12px;
|
|
44
|
+
background-color: ${({ $destructive, theme }) => {
|
|
45
|
+
if (!$destructive)
|
|
46
|
+
return 'transparent';
|
|
47
|
+
const error = theme?.colors?.error;
|
|
48
|
+
const triple = error ? hexToRgbTriple(error) : null;
|
|
49
|
+
return triple ? `rgba(${triple}, 0.1)` : 'rgba(220, 38, 38, 0.1)';
|
|
50
|
+
}};
|
|
51
|
+
color: ${({ $destructive, theme }) => {
|
|
52
|
+
if (!$destructive)
|
|
53
|
+
return 'inherit';
|
|
54
|
+
return theme?.colors?.error ?? '#dc2626';
|
|
55
|
+
}};
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
outline: none;
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
-webkit-tap-highlight-color: transparent;
|
|
60
|
+
`;
|
|
61
|
+
export function ConfirmDialog({ message, description, confirmLabel, cancelLabel, destructive = false, onConfirm, onCancel, }) {
|
|
62
|
+
const { ripple, trigger, isTarget } = useRipple();
|
|
63
|
+
const handleConfirm = (e) => {
|
|
64
|
+
trigger(e, 'confirm');
|
|
65
|
+
onConfirm();
|
|
66
|
+
};
|
|
67
|
+
const handleCancel = (e) => {
|
|
68
|
+
trigger(e, 'cancel');
|
|
69
|
+
onCancel();
|
|
70
|
+
};
|
|
71
|
+
return (_jsxs(DialogContainer, { children: [_jsx(DialogMessage, { children: message }), description && _jsx(DialogDescription, { children: description }), _jsxs(DialogButton, { "$destructive": destructive, onClick: handleConfirm, children: [isTarget('confirm') && ripple && (_jsx(Ripple, { "$x": ripple.x, "$y": ripple.y }, ripple.key)), confirmLabel] }), _jsxs(DialogButton, { onClick: handleCancel, children: [isTarget('cancel') && ripple && (_jsx(Ripple, { "$x": ripple.x, "$y": ripple.y }, ripple.key)), cancelLabel] })] }));
|
|
72
|
+
}
|
|
73
|
+
export default ConfirmDialog;
|
|
74
|
+
//# sourceMappingURL=confirm-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-dialog.js","sourceRoot":"","sources":["../src/confirm-dialog.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { BOUNCE_CURVE, PRESS_SCALE_PRIMARY, PRESS_SCALE_SUBTLE, pressPrimary, pressSubtle, pressPrimaryScale, pressSubtleScale, } from './press.js';
|
|
2
2
|
export { useAnimatedAction } from './use-animated-action.js';
|
|
3
|
+
export { useViewportSize } from './use-viewport-size.js';
|
|
4
|
+
export type { ViewportSize } from './use-viewport-size.js';
|
|
3
5
|
export { actionSheetContainer, actionSheetList, actionSheetRow, } from './action-sheet.js';
|
|
4
6
|
export { Ripple, rippleAnimation, useRipple } from './ripple.js';
|
|
5
7
|
export type { RippleState } from './ripple.js';
|
|
@@ -13,9 +15,19 @@ export { default as CircleIconButton } from './circle-icon-button.js';
|
|
|
13
15
|
export type { CircleIconButtonProps, CircleIconName } from './circle-icon-button.js';
|
|
14
16
|
export { default as BannerButton } from './banner-button.js';
|
|
15
17
|
export type { BannerButtonProps } from './banner-button.js';
|
|
18
|
+
export { Badge } from './badge.js';
|
|
19
|
+
export type { BadgeProps, BadgeVariant } from './badge.js';
|
|
20
|
+
export { default as ToggleSwitch } from './toggle-switch.js';
|
|
21
|
+
export type { ToggleSwitchProps } from './toggle-switch.js';
|
|
22
|
+
export { ConfirmDialog } from './confirm-dialog.js';
|
|
23
|
+
export type { ConfirmDialogProps } from './confirm-dialog.js';
|
|
24
|
+
export { BottomSheet } from './bottom-sheet.js';
|
|
25
|
+
export type { BottomSheetProps } from './bottom-sheet.js';
|
|
16
26
|
export { buildTheme, theme, hexToRgb } from './theme.js';
|
|
17
27
|
export type { ThemeType } from './theme.js';
|
|
18
28
|
export { lightPalette, darkPalette } from './palettes.js';
|
|
19
29
|
export type { ModeColorPalette } from './palettes.js';
|
|
20
30
|
export type { DynamicLanguage, CharacterPreference, StaticLanguage, } from './language.js';
|
|
31
|
+
export { ListItem, UnorderedListItemContainer } from './list-item.js';
|
|
32
|
+
export type { ListItemProps, ListItemIconName, ListItemActionName, } from './list-item.js';
|
|
21
33
|
//# 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,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EACN,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACtE,YAAY,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EACN,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACtE,YAAY,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,YAAY,EACX,eAAe,EACf,mBAAmB,EACnB,cAAc,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,QAAQ,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACtE,YAAY,EACX,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { BOUNCE_CURVE, PRESS_SCALE_PRIMARY, PRESS_SCALE_SUBTLE, pressPrimary, pressSubtle, pressPrimaryScale, pressSubtleScale, } from './press.js';
|
|
2
2
|
export { useAnimatedAction } from './use-animated-action.js';
|
|
3
|
+
export { useViewportSize } from './use-viewport-size.js';
|
|
3
4
|
export { actionSheetContainer, actionSheetList, actionSheetRow, } from './action-sheet.js';
|
|
4
5
|
export { Ripple, rippleAnimation, useRipple } from './ripple.js';
|
|
5
6
|
export { SPRING_COMFORTABLE, SPRING_COMFORTABLE_SLOW, SPRING_SNAPPY, SPRING_RESPONSIVE, SPRING_STAGGERED, SPRING_INSTANT, SPRING_GENTLE, SPRING_VERY_SLOW, SPRING_LANDING, SPRING_RISING, } from './spring.js';
|
|
@@ -7,6 +8,11 @@ export { default as AnimatedText } from './animated-text.js';
|
|
|
7
8
|
export { default as BackButton } from './back-button.js';
|
|
8
9
|
export { default as CircleIconButton } from './circle-icon-button.js';
|
|
9
10
|
export { default as BannerButton } from './banner-button.js';
|
|
11
|
+
export { Badge } from './badge.js';
|
|
12
|
+
export { default as ToggleSwitch } from './toggle-switch.js';
|
|
13
|
+
export { ConfirmDialog } from './confirm-dialog.js';
|
|
14
|
+
export { BottomSheet } from './bottom-sheet.js';
|
|
10
15
|
export { buildTheme, theme, hexToRgb } from './theme.js';
|
|
11
16
|
export { lightPalette, darkPalette } from './palettes.js';
|
|
17
|
+
export { ListItem, UnorderedListItemContainer } from './list-item.js';
|
|
12
18
|
//# 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,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,EACN,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,EACN,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAS1D,OAAO,EAAE,QAAQ,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ListItem + UnorderedListItemContainer — a pressable settings/menu row and its
|
|
3
|
+
* list wrapper.
|
|
4
|
+
*
|
|
5
|
+
* Ported from ymy-components (`./collections/ListItem` + `./collections/
|
|
6
|
+
* ListItem.styles`), preserving the exact public API the xunzi call sites
|
|
7
|
+
* (`AuthSection`, `Profile`) drive, so re-pointing them at kang is a pure import
|
|
8
|
+
* swap. A row renders a leading icon, a label, and a trailing action (a chevron,
|
|
9
|
+
* or an inline Material toggle when `actionIcon === 'switch'`), with a Material
|
|
10
|
+
* ripple on press.
|
|
11
|
+
*
|
|
12
|
+
* kang-specific upgrades / adaptations:
|
|
13
|
+
* - **Press feedback** uses kang's shared `Ripple` / `useRipple` primitives
|
|
14
|
+
* (themed off `theme.colors.ripple`), replacing ymy's bespoke ripple wiring.
|
|
15
|
+
* - **Icons:** ymy hard-depended on `react-icons` (MdTranslate / MdOutlineWbSunny
|
|
16
|
+
* / MdChevronRight). To keep kang dependency-light and domain-free, the same
|
|
17
|
+
* glyphs ship as inline SVGs (identical Material-icons path data), selectable
|
|
18
|
+
* via the `icon` string. Consumers may override the leading glyph with any node
|
|
19
|
+
* via `iconNode` — the same override pattern as BackButton / CircleIconButton.
|
|
20
|
+
* - **Text:** the `textContent` path maps the app's `DynamicLanguage` model onto
|
|
21
|
+
* kang's domain-free `AnimatedText` (`variants` / `staticIndex` / `sizers`),
|
|
22
|
+
* exactly as xunzi's AnimatedText adapter does — so language knowledge stays in
|
|
23
|
+
* the shared language types and the motion stays in `AnimatedText`.
|
|
24
|
+
* - **Toggle:** ymy rendered a separate `ToggleSwitch`; that Material toggle is
|
|
25
|
+
* inlined (controlled or uncontrolled) so kang needn't ship a ToggleSwitch yet.
|
|
26
|
+
*
|
|
27
|
+
* `styled-components`, `@react-spring/web` (via AnimatedText) and `react` are the
|
|
28
|
+
* only things this module pulls in, all optional peer deps.
|
|
29
|
+
*/
|
|
30
|
+
import { type CSSProperties, type ReactElement, type ReactNode } from 'react';
|
|
31
|
+
import type { CharacterPreference, DynamicLanguage, StaticLanguage } from './language.js';
|
|
32
|
+
/** The built-in leading icons a row can render (was ymy's `PrimaryIcons`). */
|
|
33
|
+
export type ListItemIconName = 'translate' | 'sunny' | 'character';
|
|
34
|
+
/** The built-in trailing actions a row can render (was ymy's `SecondaryIconName`). */
|
|
35
|
+
export type ListItemActionName = 'chevron' | 'switch';
|
|
36
|
+
export type ListItemProps = {
|
|
37
|
+
/** Which built-in leading icon to render. Ignored when `iconNode` is provided. */
|
|
38
|
+
icon: ListItemIconName;
|
|
39
|
+
/**
|
|
40
|
+
* An explicit leading-icon node, overriding the built-in `icon`. Lets
|
|
41
|
+
* consumers supply their own glyph without kang depending on an icon library —
|
|
42
|
+
* the same override pattern as BackButton / CircleIconButton.
|
|
43
|
+
*/
|
|
44
|
+
iconNode?: ReactNode;
|
|
45
|
+
/** Plain-text label (used when `textContent` is absent). */
|
|
46
|
+
text?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Multilingual label. When present it renders kang's cross-fading
|
|
49
|
+
* {@link AnimatedText}, cycling english ⇄ chinese per `characterPreference`.
|
|
50
|
+
*/
|
|
51
|
+
textContent?: DynamicLanguage;
|
|
52
|
+
/** Which character set (`simplified`/`traditional`) the chinese variant uses. */
|
|
53
|
+
characterPreference?: CharacterPreference;
|
|
54
|
+
/** Cross-fade the label (true) or hold a single static variant (false). Default true. */
|
|
55
|
+
animate?: boolean;
|
|
56
|
+
/** Max ms between cross-fade cycles, forwarded to AnimatedText. */
|
|
57
|
+
maxDelay?: number;
|
|
58
|
+
/** Trailing action: a chevron (default) or an inline toggle. */
|
|
59
|
+
actionIcon?: ListItemActionName;
|
|
60
|
+
/** Row click handler (used when `actionIcon !== 'switch'`). */
|
|
61
|
+
onClick?: () => void;
|
|
62
|
+
/** Inline style passthrough on the `<li>`. */
|
|
63
|
+
styles?: CSSProperties;
|
|
64
|
+
/** Toggle state when `actionIcon === 'switch'` (controlled). */
|
|
65
|
+
switchChecked?: boolean;
|
|
66
|
+
/** Fired with the next toggle value when `actionIcon === 'switch'`. */
|
|
67
|
+
onSwitchChange?: (checked: boolean) => void;
|
|
68
|
+
/** Which language to show when `animate` is false. Forwarded to AnimatedText. */
|
|
69
|
+
staticLanguage?: StaticLanguage;
|
|
70
|
+
};
|
|
71
|
+
export declare const ListItem: ({ icon, iconNode, text, textContent, characterPreference, animate, maxDelay, actionIcon, onClick, styles, switchChecked, onSwitchChange, staticLanguage, }: ListItemProps) => ReactElement;
|
|
72
|
+
export { UnorderedListItemContainer } from './list-item.styles.js';
|
|
73
|
+
export default ListItem;
|
|
74
|
+
//# sourceMappingURL=list-item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-item.d.ts","sourceRoot":"","sources":["../src/list-item.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAGN,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EACX,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,MAAM,eAAe,CAAC;AAcvB,8EAA8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;AACnE,sFAAsF;AACtF,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAmFtD,MAAM,MAAM,aAAa,GAAG;IAC3B,kFAAkF;IAClF,IAAI,EAAE,gBAAgB,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,yFAAyF;IACzF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,iFAAiF;IACjF,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC,CAAC;AAoCF,eAAO,MAAM,QAAQ,+JAclB,aAAa,KAAG,YA2DlB,CAAC;AAEF,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEnE,eAAe,QAAQ,CAAC"}
|