@seed-design/lynx-react 0.4.0 → 0.5.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/lib/components/Accordion/Accordion.d.ts +56 -0
- package/lib/components/Accordion/Accordion.d.ts.map +1 -0
- package/lib/components/Accordion/Accordion.jsx +210 -0
- package/lib/components/Accordion/Accordion.namespace.d.ts +2 -0
- package/lib/components/Accordion/Accordion.namespace.d.ts.map +1 -0
- package/lib/components/Accordion/Accordion.namespace.js +17 -0
- package/lib/components/Accordion/index.d.ts +3 -0
- package/lib/components/Accordion/index.d.ts.map +1 -0
- package/lib/components/ActionButton/ActionButton.jsx +6 -6
- package/lib/components/AppBar/AppBar.jsx +1 -1
- package/lib/components/Badge/Badge.jsx +1 -1
- package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/lib/components/BottomSheet/BottomSheet.jsx +6 -3
- package/lib/components/Box/Box.jsx +1 -1
- package/lib/components/Callout/Callout.d.ts +32 -0
- package/lib/components/Callout/Callout.d.ts.map +1 -0
- package/lib/components/Callout/Callout.jsx +113 -0
- package/lib/components/Callout/Callout.namespace.d.ts +2 -0
- package/lib/components/Callout/Callout.namespace.d.ts.map +1 -0
- package/lib/components/Callout/Callout.namespace.js +13 -0
- package/lib/components/Callout/index.d.ts +3 -0
- package/lib/components/Callout/index.d.ts.map +1 -0
- package/lib/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/lib/components/Checkbox/Checkbox.jsx +36 -5
- package/lib/components/Chip/Chip.d.ts +66 -0
- package/lib/components/Chip/Chip.d.ts.map +1 -0
- package/lib/components/Chip/Chip.jsx +159 -0
- package/lib/components/Chip/Chip.namespace.d.ts +2 -0
- package/lib/components/Chip/Chip.namespace.d.ts.map +1 -0
- package/lib/components/Chip/Chip.namespace.js +16 -0
- package/lib/components/Chip/index.d.ts +3 -0
- package/lib/components/Chip/index.d.ts.map +1 -0
- package/lib/components/Divider/Divider.d.ts +31 -0
- package/lib/components/Divider/Divider.d.ts.map +1 -0
- package/lib/components/Divider/Divider.jsx +26 -0
- package/lib/components/Divider/index.d.ts +2 -0
- package/lib/components/Divider/index.d.ts.map +1 -0
- package/lib/components/Field/Field.jsx +1 -1
- package/lib/components/Icon/Icon.jsx +2 -2
- package/lib/components/ProgressCircle/ProgressCircle.d.ts.map +1 -1
- package/lib/components/ProgressCircle/ProgressCircle.jsx +38 -7
- package/lib/components/RadioGroup/RadioGroup.jsx +2 -2
- package/lib/components/Stack/Stack.d.ts.map +1 -1
- package/lib/components/Stack/Stack.jsx +11 -2
- package/lib/components/Switch/Switch.jsx +2 -2
- package/lib/components/Tabs/Tabs.d.ts +59 -0
- package/lib/components/Tabs/Tabs.d.ts.map +1 -0
- package/lib/components/Tabs/Tabs.jsx +406 -0
- package/lib/components/Tabs/Tabs.namespace.d.ts +2 -0
- package/lib/components/Tabs/Tabs.namespace.d.ts.map +1 -0
- package/lib/components/Tabs/Tabs.namespace.js +14 -0
- package/lib/components/Tabs/index.d.ts +3 -0
- package/lib/components/Tabs/index.d.ts.map +1 -0
- package/lib/components/TagGroup/TagGroup.d.ts +2 -1
- package/lib/components/TagGroup/TagGroup.d.ts.map +1 -1
- package/lib/components/TagGroup/TagGroup.jsx +4 -3
- package/lib/components/Text/Text.jsx +2 -2
- package/lib/components/TextField/TextField.d.ts +20 -2
- package/lib/components/TextField/TextField.d.ts.map +1 -1
- package/lib/components/TextField/TextField.jsx +25 -9
- package/lib/components/index.d.ts +5 -0
- package/lib/components/index.d.ts.map +1 -1
- package/lib/hooks/useIconColor.d.ts +2 -1
- package/lib/hooks/useIconColor.d.ts.map +1 -1
- package/lib/hooks/useIconColor.js +29 -5
- package/lib/hooks/usePressTap.d.ts.map +1 -1
- package/lib/hooks/usePressTap.js +1 -0
- package/lib/index.js +14 -5
- package/lib/utils/create-slot-recipe-context.jsx +1 -1
- package/package.json +3 -3
- package/src/components/Accordion/Accordion.namespace.ts +22 -0
- package/src/components/Accordion/Accordion.test.tsx +129 -0
- package/src/components/Accordion/Accordion.tsx +453 -0
- package/src/components/Accordion/index.ts +24 -0
- package/src/components/BottomSheet/BottomSheet.test.tsx +24 -0
- package/src/components/BottomSheet/BottomSheet.tsx +14 -2
- package/src/components/Callout/Callout.namespace.ts +14 -0
- package/src/components/Callout/Callout.test.tsx +188 -0
- package/src/components/Callout/Callout.tsx +272 -0
- package/src/components/Callout/index.ts +16 -0
- package/src/components/Checkbox/Checkbox.test.tsx +176 -0
- package/src/components/Checkbox/Checkbox.tsx +36 -2
- package/src/components/Chip/Chip.namespace.ts +20 -0
- package/src/components/Chip/Chip.test.tsx +113 -0
- package/src/components/Chip/Chip.tsx +373 -0
- package/src/components/Chip/index.ts +22 -0
- package/src/components/Divider/Divider.test.tsx +73 -0
- package/src/components/Divider/Divider.tsx +76 -0
- package/src/components/Divider/index.ts +1 -0
- package/src/components/Icon/Icon.test.tsx +129 -0
- package/src/components/ProgressCircle/ProgressCircle.test.tsx +58 -0
- package/src/components/ProgressCircle/ProgressCircle.tsx +42 -5
- package/src/components/Stack/Stack.test.tsx +67 -0
- package/src/components/Stack/Stack.tsx +15 -1
- package/src/components/Tabs/Tabs.namespace.ts +16 -0
- package/src/components/Tabs/Tabs.test.tsx +181 -0
- package/src/components/Tabs/Tabs.tsx +706 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/TagGroup/TagGroup.test.tsx +73 -0
- package/src/components/TagGroup/TagGroup.tsx +4 -2
- package/src/components/TextField/TextField.test.tsx +163 -35
- package/src/components/TextField/TextField.tsx +61 -19
- package/src/components/index.ts +5 -0
- package/src/hooks/useIconColor.ts +43 -5
- package/src/hooks/usePressTap.test.ts +13 -0
- package/src/hooks/usePressTap.ts +1 -0
|
@@ -3,14 +3,20 @@ import { InternalIcon } from "../Icon/Icon.jsx";
|
|
|
3
3
|
import { useFieldContext } from "../Field/context.js";
|
|
4
4
|
import { useKeyboardAvoidanceActions } from "../KeyboardAvoidingScrollView/context.js";
|
|
5
5
|
import { NATIVE_TEXT_MAX_LENGTH_UNLIMITED, TextFieldContext } from "./context.js";
|
|
6
|
-
import { textInput } from "@seed-design/lynx-css/vars/component";
|
|
7
|
-
import clsx from "clsx";
|
|
8
6
|
import * as React from "@lynx-js/react";
|
|
7
|
+
import clsx from "clsx";
|
|
8
|
+
import { textInput } from "@seed-design/lynx-css/vars/component";
|
|
9
9
|
import { textInput as textInput$1 } from "@seed-design/lynx-css/recipes/text-input";
|
|
10
10
|
//#region src/components/TextField/TextField.tsx
|
|
11
11
|
var ANDROID_TEXTAREA_DEFAULT_LINE_SPACING = "3.2px";
|
|
12
|
+
function getRuntimePlatform() {
|
|
13
|
+
return (globalThis.SystemInfo ?? (typeof SystemInfo === "undefined" ? void 0 : SystemInfo))?.platform;
|
|
14
|
+
}
|
|
12
15
|
function isAndroidRuntime() {
|
|
13
|
-
return (
|
|
16
|
+
return getRuntimePlatform() === "Android";
|
|
17
|
+
}
|
|
18
|
+
function isIOSRuntime() {
|
|
19
|
+
return getRuntimePlatform() === "iOS";
|
|
14
20
|
}
|
|
15
21
|
var { ClassNamesProvider, useClassNames } = createSlotRecipeContext(textInput$1);
|
|
16
22
|
var TextFieldRoot = React.forwardRef((props, forwardedRef) => {
|
|
@@ -340,7 +346,7 @@ var TextFieldInput = React.forwardRef((props, ref) => {
|
|
|
340
346
|
{displayValue}
|
|
341
347
|
</text>;
|
|
342
348
|
}
|
|
343
|
-
return <input {...control.defaultValueProps} ref={control.mergedRef} className={clsx(classes.value, className)} disabled={control.disabled} readonly={control.readOnly} show-soft-input-on-focus={
|
|
349
|
+
return <input {...control.defaultValueProps} ref={control.mergedRef} className={clsx(classes.value, className)} disabled={control.disabled} readonly={control.readOnly} show-soft-input-on-focus={showSoftInputOnFocus ?? true} android-set-soft-input-mode={androidSetSoftInputMode ?? "unspecified"} name={name ?? control.context.name} {...resolvedMaxLength === void 0 ? {} : { maxlength: resolvedMaxLength }} bindinput={control.handleInput} bindselection={handleSelection} bindfocus={control.handleFocus} bindblur={control.handleBlur} {...nativeProps} />;
|
|
344
350
|
});
|
|
345
351
|
TextFieldInput.displayName = "TextFieldInput";
|
|
346
352
|
var TextFieldTextarea = React.forwardRef((props, ref) => {
|
|
@@ -356,17 +362,27 @@ var TextFieldTextarea = React.forwardRef((props, ref) => {
|
|
|
356
362
|
});
|
|
357
363
|
const resolvedMaxLength = useResolvedNativeMaxLength(maxlength, control.nativeInsertionMaxLength);
|
|
358
364
|
const isAndroid = isAndroidRuntime();
|
|
365
|
+
const usesIOSAutoresizeWrapper = autoresize && isIOSRuntime();
|
|
359
366
|
const resolvedLineSpacing = lineSpacing !== void 0 ? lineSpacing : isAndroid ? ANDROID_TEXTAREA_DEFAULT_LINE_SPACING : void 0;
|
|
360
367
|
const handleSelection = React.useCallback((event) => {
|
|
361
368
|
"background only";
|
|
362
369
|
control.handleSelectionChange(event.detail);
|
|
363
370
|
bindselection?.(event);
|
|
364
371
|
}, [bindselection, control.handleSelectionChange]);
|
|
372
|
+
const handleLayoutChange = React.useCallback((event) => {
|
|
373
|
+
"background only";
|
|
374
|
+
if (autoresize) control.notifyLayoutChanged();
|
|
375
|
+
bindlayoutchange?.(event);
|
|
376
|
+
}, [
|
|
377
|
+
autoresize,
|
|
378
|
+
bindlayoutchange,
|
|
379
|
+
control.notifyLayoutChanged
|
|
380
|
+
]);
|
|
365
381
|
const handleTextareaRootTap = React.useCallback((event) => {
|
|
366
382
|
"background only";
|
|
367
|
-
if (event.target.uid !== event.currentTarget.uid) return;
|
|
383
|
+
if (control.disabled || event.target.uid !== event.currentTarget.uid) return;
|
|
368
384
|
control.focusNativeControl();
|
|
369
|
-
}, [control.focusNativeControl]);
|
|
385
|
+
}, [control.disabled, control.focusNativeControl]);
|
|
370
386
|
if (control.readOnly) {
|
|
371
387
|
const value = control.context.value;
|
|
372
388
|
const isPlaceholder = value === "";
|
|
@@ -379,9 +395,9 @@ var TextFieldTextarea = React.forwardRef((props, ref) => {
|
|
|
379
395
|
{isPlaceholder ? props.placeholder : value}
|
|
380
396
|
</text>;
|
|
381
397
|
}
|
|
382
|
-
const textarea = <textarea {...control.defaultValueProps} ref={control.mergedRef} className={clsx(classes.value, classes.textareaValue, autoresize
|
|
383
|
-
if (!
|
|
384
|
-
return <view className={clsx(classes.textareaRoot,
|
|
398
|
+
const textarea = <textarea {...control.defaultValueProps} ref={control.mergedRef} className={clsx(classes.value, classes.textareaValue, !autoresize && classes.textareaFixed, usesIOSAutoresizeWrapper && classes.textareaNativeAutoresize, autoresize && !usesIOSAutoresizeWrapper && classes.textareaAndroidAutoresize, className)} disabled={control.disabled} readonly={control.readOnly} show-soft-input-on-focus={showSoftInputOnFocus ?? true} bounces={bounces ?? (autoresize ? false : void 0)} line-spacing={resolvedLineSpacing} android-fullscreen-mode={androidFullscreenMode ?? false} android-set-soft-input-mode={androidSetSoftInputMode ?? "unspecified"} name={name ?? control.context.name} {...resolvedMaxLength === void 0 ? {} : { maxlength: resolvedMaxLength }} bindinput={control.handleInput} bindselection={handleSelection} bindfocus={control.handleFocus} bindblur={control.handleBlur} bindlayoutchange={usesIOSAutoresizeWrapper ? bindlayoutchange : handleLayoutChange} {...nativeProps} />;
|
|
399
|
+
if (!usesIOSAutoresizeWrapper) return textarea;
|
|
400
|
+
return <view ignore-focus={true} className={clsx(classes.textareaRoot, classes.textareaAutoresizeRoot)} bindtap={handleTextareaRootTap} bindlayoutchange={control.notifyLayoutChanged}>
|
|
385
401
|
{textarea}
|
|
386
402
|
</view>;
|
|
387
403
|
});
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
export * from './Accordion';
|
|
1
2
|
export * from './ActionButton';
|
|
2
3
|
export * from './AppBar';
|
|
3
4
|
export * from './Badge';
|
|
4
5
|
export * from './Box';
|
|
5
6
|
export * from './BottomSheet';
|
|
7
|
+
export * from './Callout';
|
|
6
8
|
export * from './Checkbox';
|
|
9
|
+
export * from './Chip';
|
|
10
|
+
export * from './Divider';
|
|
7
11
|
export * from './Field';
|
|
8
12
|
export * from './Icon';
|
|
9
13
|
export * from './KeyboardAvoidingScrollView';
|
|
@@ -11,6 +15,7 @@ export * from './ProgressCircle';
|
|
|
11
15
|
export * from './RadioGroup';
|
|
12
16
|
export * from './Stack';
|
|
13
17
|
export * from './Switch';
|
|
18
|
+
export * from './Tabs';
|
|
14
19
|
export * from './TagGroup';
|
|
15
20
|
export * from './Text';
|
|
16
21
|
export * from './TextField';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC"}
|
|
@@ -5,7 +5,8 @@ export interface UseIconColorOptions {
|
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Lynx `<image>` 의 tint color 를 recipe 의 CSS `color` 로부터 main-thread 에서 읽어
|
|
8
|
-
* `tint-color` attribute 로 mirror. `deps` 가 바뀌면
|
|
8
|
+
* `tint-color` attribute 로 mirror. `deps` 가 바뀌면 native class patch가 반영된
|
|
9
|
+
* 다음 frame에 재동기화하고, UI 표시 이벤트에서는 즉시 동기화.
|
|
9
10
|
*
|
|
10
11
|
* ```tsx
|
|
11
12
|
* const iconColorProps = useIconColor([variant, disabled, loading]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useIconColor.d.ts","sourceRoot":"","sources":["../../src/hooks/useIconColor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAOhE,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"useIconColor.d.ts","sourceRoot":"","sources":["../../src/hooks/useIconColor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAOhE,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;CAC3C;AA0DD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE,mBAAmB,GAC5B;IACD,GAAG,EAAE,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,0BAA0B,EAAE,MAAM,IAAI,CAAC;CACxC,CAmBA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { runOnMainThread, useEffect, useMainThreadRef } from "@lynx-js/react";
|
|
2
2
|
//#region src/hooks/useIconColor.ts
|
|
3
|
-
function
|
|
3
|
+
function syncTintColorOnce(targetRef, sourceRef) {
|
|
4
4
|
"main thread";
|
|
5
5
|
const target = targetRef.current;
|
|
6
6
|
if (!target) return;
|
|
@@ -8,11 +8,31 @@ function syncTintColor(targetRef, sourceRef) {
|
|
|
8
8
|
let color;
|
|
9
9
|
if (typeof source.getComputedStyleProperty === "function") color = source.getComputedStyleProperty("color");
|
|
10
10
|
else if (typeof source.getComputedCssProperty === "function") color = source.getComputedCssProperty("color");
|
|
11
|
-
if (color) target.setAttribute("tint-color", color);
|
|
11
|
+
if (color && target.getAttribute("tint-color") !== color) target.setAttribute("tint-color", color);
|
|
12
|
+
}
|
|
13
|
+
function scheduleTintColorSync(targetRef, sourceRef, frameRef) {
|
|
14
|
+
"main thread";
|
|
15
|
+
if (frameRef.current && typeof cancelAnimationFrame === "function") {
|
|
16
|
+
cancelAnimationFrame(frameRef.current);
|
|
17
|
+
frameRef.current = 0;
|
|
18
|
+
}
|
|
19
|
+
if (typeof requestAnimationFrame === "function") frameRef.current = requestAnimationFrame(() => {
|
|
20
|
+
frameRef.current = 0;
|
|
21
|
+
syncTintColorOnce(targetRef, sourceRef);
|
|
22
|
+
});
|
|
23
|
+
else syncTintColorOnce(targetRef, sourceRef);
|
|
24
|
+
}
|
|
25
|
+
function cancelTintColorSync(frameRef) {
|
|
26
|
+
"main thread";
|
|
27
|
+
if (frameRef.current && typeof cancelAnimationFrame === "function") {
|
|
28
|
+
cancelAnimationFrame(frameRef.current);
|
|
29
|
+
frameRef.current = 0;
|
|
30
|
+
}
|
|
12
31
|
}
|
|
13
32
|
/**
|
|
14
33
|
* Lynx `<image>` 의 tint color 를 recipe 의 CSS `color` 로부터 main-thread 에서 읽어
|
|
15
|
-
* `tint-color` attribute 로 mirror. `deps` 가 바뀌면
|
|
34
|
+
* `tint-color` attribute 로 mirror. `deps` 가 바뀌면 native class patch가 반영된
|
|
35
|
+
* 다음 frame에 재동기화하고, UI 표시 이벤트에서는 즉시 동기화.
|
|
16
36
|
*
|
|
17
37
|
* ```tsx
|
|
18
38
|
* const iconColorProps = useIconColor([variant, disabled, loading]);
|
|
@@ -22,12 +42,16 @@ function syncTintColor(targetRef, sourceRef) {
|
|
|
22
42
|
function useIconColor(deps, options) {
|
|
23
43
|
const ref = useMainThreadRef(null);
|
|
24
44
|
const sourceRef = options?.sourceRef;
|
|
45
|
+
const frameRef = useMainThreadRef(0);
|
|
25
46
|
function syncOnUiAppear() {
|
|
26
47
|
"main thread";
|
|
27
|
-
|
|
48
|
+
syncTintColorOnce(ref, sourceRef);
|
|
28
49
|
}
|
|
29
50
|
useEffect(() => {
|
|
30
|
-
runOnMainThread(
|
|
51
|
+
runOnMainThread(scheduleTintColorSync)(ref, sourceRef, frameRef);
|
|
52
|
+
return () => {
|
|
53
|
+
runOnMainThread(cancelTintColorSync)(frameRef);
|
|
54
|
+
};
|
|
31
55
|
}, deps);
|
|
32
56
|
return {
|
|
33
57
|
ref,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePressTap.d.ts","sourceRoot":"","sources":["../../src/hooks/usePressTap.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,KAAK,YAAY,GAAG,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,eAAe,CAAC,EAAE,cAAc,CAAC,qBAAqB,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,YAAY,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,YAAY,CAAC;IAC9B,qBAAqB,CAAC,EAAE,cAAc,CAAC,qBAAqB,CAAC,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"usePressTap.d.ts","sourceRoot":"","sources":["../../src/hooks/usePressTap.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,KAAK,YAAY,GAAG,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,eAAe,CAAC,EAAE,cAAc,CAAC,qBAAqB,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,YAAY,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,YAAY,CAAC;IAC9B,qBAAqB,CAAC,EAAE,cAAc,CAAC,qBAAqB,CAAC,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CA2B/E"}
|
package/lib/hooks/usePressTap.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { useControllableState } from "./hooks/useControllableState.js";
|
|
1
2
|
import { usePressTap } from "./hooks/usePressTap.js";
|
|
2
3
|
import { createSlotRecipeContext } from "./utils/create-slot-recipe-context.jsx";
|
|
3
|
-
import {
|
|
4
|
+
import { useIconColor } from "./hooks/useIconColor.js";
|
|
4
5
|
import { useSafeArea } from "./hooks/useSafeArea.js";
|
|
6
|
+
import { Icon, PrefixIcon, SuffixIcon } from "./components/Icon/Icon.jsx";
|
|
7
|
+
import { AccordionBody, AccordionContent, AccordionDescription, AccordionHeader, AccordionItem, AccordionPrefix, AccordionRoot, AccordionSuffixIcon, AccordionTitle, AccordionTrigger } from "./components/Accordion/Accordion.jsx";
|
|
8
|
+
import { Accordion_namespace_exports } from "./components/Accordion/Accordion.namespace.js";
|
|
9
|
+
import { capitalize, resolveRecipeToken } from "./utils/resolve-recipe-token.js";
|
|
5
10
|
import { ProgressCircleRange, ProgressCircleRoot } from "./components/ProgressCircle/ProgressCircle.jsx";
|
|
6
11
|
import { ProgressCircle_namespace_exports } from "./components/ProgressCircle/ProgressCircle.namespace.js";
|
|
7
|
-
import { useIconColor } from "./hooks/useIconColor.js";
|
|
8
|
-
import { Icon, PrefixIcon, SuffixIcon } from "./components/Icon/Icon.jsx";
|
|
9
12
|
import { ActionButton } from "./components/ActionButton/ActionButton.jsx";
|
|
10
13
|
import { AppBarIconButton, AppBarLeft, AppBarMain, AppBarRight, AppBarRoot, AppBarSlot, AppBarSubtitle, AppBarTitle } from "./components/AppBar/AppBar.jsx";
|
|
11
14
|
import { AppBar_namespace_exports } from "./components/AppBar/AppBar.namespace.js";
|
|
@@ -13,10 +16,14 @@ import { Badge } from "./components/Badge/Badge.jsx";
|
|
|
13
16
|
import { Box } from "./components/Box/Box.jsx";
|
|
14
17
|
import { BottomSheetBackdrop, BottomSheetBody, BottomSheetContent, BottomSheetDescription, BottomSheetFooter, BottomSheetHandle, BottomSheetHeader, BottomSheetPositioner, BottomSheetRoot, BottomSheetTitle, BottomSheetTrigger } from "./components/BottomSheet/BottomSheet.jsx";
|
|
15
18
|
import { BottomSheet_namespace_exports } from "./components/BottomSheet/BottomSheet.namespace.js";
|
|
16
|
-
import {
|
|
19
|
+
import { CalloutCloseButton, CalloutContent, CalloutDescription, CalloutLink, CalloutRoot, CalloutTitle } from "./components/Callout/Callout.jsx";
|
|
20
|
+
import { Callout_namespace_exports } from "./components/Callout/Callout.namespace.js";
|
|
17
21
|
import { splitMultipleVariantsProps } from "./utils/split-multiple-variants-props.js";
|
|
18
22
|
import { CheckboxControl, CheckboxGroup, CheckboxIndicator, CheckboxLabel, CheckboxRoot } from "./components/Checkbox/Checkbox.jsx";
|
|
19
23
|
import { Checkbox_namespace_exports } from "./components/Checkbox/Checkbox.namespace.js";
|
|
24
|
+
import { ChipButton, ChipLabel, ChipPrefixAvatar, ChipPrefixIcon, ChipRadioItem, ChipRadioRoot, ChipRoot, ChipSuffixIcon, ChipToggle } from "./components/Chip/Chip.jsx";
|
|
25
|
+
import { Chip_namespace_exports } from "./components/Chip/Chip.namespace.js";
|
|
26
|
+
import { Divider } from "./components/Divider/Divider.jsx";
|
|
20
27
|
import { FieldCharacterCount, FieldDescription, FieldErrorMessage, FieldFooter, FieldHeader, FieldIndicatorText, FieldLabel, FieldRequiredIndicator, FieldRoot } from "./components/Field/Field.jsx";
|
|
21
28
|
import { Field_namespace_exports } from "./components/Field/Field.namespace.js";
|
|
22
29
|
import { KeyboardAvoidingScrollView } from "./components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.jsx";
|
|
@@ -25,6 +32,8 @@ import { RadioGroup_namespace_exports } from "./components/RadioGroup/RadioGroup
|
|
|
25
32
|
import { HStack, VStack } from "./components/Stack/Stack.jsx";
|
|
26
33
|
import { SwitchControl, SwitchLabel, SwitchRoot, SwitchThumb } from "./components/Switch/Switch.jsx";
|
|
27
34
|
import { Switch_namespace_exports } from "./components/Switch/Switch.namespace.js";
|
|
35
|
+
import { TabsCarousel, TabsCarouselCamera, TabsContent, TabsIndicator, TabsList, TabsRoot, TabsTrigger } from "./components/Tabs/Tabs.jsx";
|
|
36
|
+
import { Tabs_namespace_exports } from "./components/Tabs/Tabs.namespace.js";
|
|
28
37
|
import { TagGroupItem, TagGroupItemLabel, TagGroupRoot } from "./components/TagGroup/TagGroup.jsx";
|
|
29
38
|
import { TagGroup_namespace_exports } from "./components/TagGroup/TagGroup.namespace.js";
|
|
30
39
|
import { Text } from "./components/Text/Text.jsx";
|
|
@@ -33,4 +42,4 @@ import { useTextFieldWithGraphemes } from "./components/TextField/useTextFieldWi
|
|
|
33
42
|
import { TextField_namespace_exports } from "./components/TextField/TextField.namespace.js";
|
|
34
43
|
import { getSeedClassName } from "./utils/get-seed-class-name.js";
|
|
35
44
|
import { useSeedClassName } from "./hooks/useSeedClassName.js";
|
|
36
|
-
export { ActionButton, AppBar_namespace_exports as AppBar, AppBarIconButton, AppBarLeft, AppBarMain, AppBarRight, AppBarRoot, AppBarSlot, AppBarSubtitle, AppBarTitle, Badge, BottomSheet_namespace_exports as BottomSheet, BottomSheetBackdrop, BottomSheetBody, BottomSheetContent, BottomSheetDescription, BottomSheetFooter, BottomSheetHandle, BottomSheetHeader, BottomSheetPositioner, BottomSheetRoot, BottomSheetTitle, BottomSheetTrigger, Box, Checkbox_namespace_exports as Checkbox, CheckboxControl, CheckboxGroup, CheckboxIndicator, CheckboxLabel, CheckboxRoot, Field_namespace_exports as Field, FieldCharacterCount, FieldDescription, FieldErrorMessage, FieldFooter, FieldHeader, FieldIndicatorText, FieldLabel, FieldRequiredIndicator, FieldRoot, HStack, Icon, KeyboardAvoidingScrollView, PrefixIcon, ProgressCircle_namespace_exports as ProgressCircle, ProgressCircleRange, ProgressCircleRoot, RadioGroup_namespace_exports as RadioGroup, RadioGroupItem, RadioGroupItemControl, RadioGroupItemIndicator, RadioGroupItemLabel, RadioGroupRoot, SuffixIcon, Switch_namespace_exports as Switch, SwitchControl, SwitchLabel, SwitchRoot, SwitchThumb, TagGroup_namespace_exports as TagGroup, TagGroupItem, TagGroupItemLabel, TagGroupRoot, Text, TextField_namespace_exports as TextField, TextFieldInput, TextFieldPrefixIcon, TextFieldPrefixText, TextFieldRoot, TextFieldSuffixIcon, TextFieldSuffixText, TextFieldTextarea, VStack, capitalize, createSlotRecipeContext, getSeedClassName, resolveRecipeToken, splitMultipleVariantsProps, useControllableState, useIconColor, usePressTap, useSafeArea, useSeedClassName, useTextFieldWithGraphemes };
|
|
45
|
+
export { Accordion_namespace_exports as Accordion, AccordionBody, AccordionContent, AccordionDescription, AccordionHeader, AccordionItem, AccordionPrefix, AccordionRoot, AccordionSuffixIcon, AccordionTitle, AccordionTrigger, ActionButton, AppBar_namespace_exports as AppBar, AppBarIconButton, AppBarLeft, AppBarMain, AppBarRight, AppBarRoot, AppBarSlot, AppBarSubtitle, AppBarTitle, Badge, BottomSheet_namespace_exports as BottomSheet, BottomSheetBackdrop, BottomSheetBody, BottomSheetContent, BottomSheetDescription, BottomSheetFooter, BottomSheetHandle, BottomSheetHeader, BottomSheetPositioner, BottomSheetRoot, BottomSheetTitle, BottomSheetTrigger, Box, Callout_namespace_exports as Callout, CalloutCloseButton, CalloutContent, CalloutDescription, CalloutLink, CalloutRoot, CalloutTitle, Checkbox_namespace_exports as Checkbox, CheckboxControl, CheckboxGroup, CheckboxIndicator, CheckboxLabel, CheckboxRoot, Chip_namespace_exports as Chip, ChipButton, ChipLabel, ChipPrefixAvatar, ChipPrefixIcon, ChipRadioItem, ChipRadioRoot, ChipRoot, ChipSuffixIcon, ChipToggle, Divider, Field_namespace_exports as Field, FieldCharacterCount, FieldDescription, FieldErrorMessage, FieldFooter, FieldHeader, FieldIndicatorText, FieldLabel, FieldRequiredIndicator, FieldRoot, HStack, Icon, KeyboardAvoidingScrollView, PrefixIcon, ProgressCircle_namespace_exports as ProgressCircle, ProgressCircleRange, ProgressCircleRoot, RadioGroup_namespace_exports as RadioGroup, RadioGroupItem, RadioGroupItemControl, RadioGroupItemIndicator, RadioGroupItemLabel, RadioGroupRoot, SuffixIcon, Switch_namespace_exports as Switch, SwitchControl, SwitchLabel, SwitchRoot, SwitchThumb, Tabs_namespace_exports as Tabs, TabsCarousel, TabsCarouselCamera, TabsContent, TabsIndicator, TabsList, TabsRoot, TabsTrigger, TagGroup_namespace_exports as TagGroup, TagGroupItem, TagGroupItemLabel, TagGroupRoot, Text, TextField_namespace_exports as TextField, TextFieldInput, TextFieldPrefixIcon, TextFieldPrefixText, TextFieldRoot, TextFieldSuffixIcon, TextFieldSuffixText, TextFieldTextarea, VStack, capitalize, createSlotRecipeContext, getSeedClassName, resolveRecipeToken, splitMultipleVariantsProps, useControllableState, useIconColor, usePressTap, useSafeArea, useSeedClassName, useTextFieldWithGraphemes };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import clsx from "clsx";
|
|
2
1
|
import { createContext, forwardRef, useContext } from "@lynx-js/react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
3
|
//#region src/utils/create-slot-recipe-context.tsx
|
|
4
4
|
function assertNotIntrinsicComponent(Component, caller) {
|
|
5
5
|
if (typeof Component !== "string") return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-design/lynx-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/daangn/seed-design.git",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@lynx-js/react": ">=0.117.0",
|
|
36
36
|
"@lynx-js/types": ">=3.7.0",
|
|
37
|
-
"@seed-design/lynx-css": "0.0.0 || >=0.
|
|
37
|
+
"@seed-design/lynx-css": "0.0.0 || >=0.8.0 <1.0.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@lynx-js/react": "^0.117.0",
|
|
41
41
|
"@lynx-js/types": "^3.7.0",
|
|
42
|
-
"@seed-design/lynx-css": "0.
|
|
42
|
+
"@seed-design/lynx-css": "0.9.0",
|
|
43
43
|
"@testing-library/jest-dom": "^6.9.1",
|
|
44
44
|
"jsdom": "^29.0.2",
|
|
45
45
|
"preact": "npm:@lynx-js/internal-preact@10.28.4-ee7bb26",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AccordionBody as Body,
|
|
3
|
+
AccordionContent as Content,
|
|
4
|
+
AccordionDescription as Description,
|
|
5
|
+
AccordionHeader as Header,
|
|
6
|
+
AccordionItem as Item,
|
|
7
|
+
AccordionPrefix as Prefix,
|
|
8
|
+
AccordionRoot as Root,
|
|
9
|
+
AccordionSuffixIcon as SuffixIcon,
|
|
10
|
+
AccordionTitle as Title,
|
|
11
|
+
AccordionTrigger as Trigger,
|
|
12
|
+
type AccordionBodyProps as BodyProps,
|
|
13
|
+
type AccordionContentProps as ContentProps,
|
|
14
|
+
type AccordionDescriptionProps as DescriptionProps,
|
|
15
|
+
type AccordionHeaderProps as HeaderProps,
|
|
16
|
+
type AccordionItemProps as ItemProps,
|
|
17
|
+
type AccordionPrefixProps as PrefixProps,
|
|
18
|
+
type AccordionRootProps as RootProps,
|
|
19
|
+
type AccordionSuffixIconProps as SuffixIconProps,
|
|
20
|
+
type AccordionTitleProps as TitleProps,
|
|
21
|
+
type AccordionTriggerProps as TriggerProps,
|
|
22
|
+
} from "./Accordion";
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { act, fireEvent, render } from "@lynx-js/react/testing-library";
|
|
3
|
+
import type * as React from "@lynx-js/react";
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { Accordion } from "./index";
|
|
7
|
+
|
|
8
|
+
function getRenderedRoot() {
|
|
9
|
+
const root = elementTree.root;
|
|
10
|
+
|
|
11
|
+
if (!root) {
|
|
12
|
+
throw new Error("Expected Lynx render root to exist.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return root;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function TestAccordion(props: React.ComponentProps<typeof Accordion.Root> = {}) {
|
|
19
|
+
return (
|
|
20
|
+
<Accordion.Root {...props}>
|
|
21
|
+
<Accordion.Item value="first">
|
|
22
|
+
<Accordion.Header>
|
|
23
|
+
<Accordion.Trigger className="first-trigger" accessibility-label="첫 번째">
|
|
24
|
+
<Accordion.Body>
|
|
25
|
+
<Accordion.Title>첫 번째</Accordion.Title>
|
|
26
|
+
</Accordion.Body>
|
|
27
|
+
</Accordion.Trigger>
|
|
28
|
+
</Accordion.Header>
|
|
29
|
+
<Accordion.Content className="first-content">
|
|
30
|
+
<text>첫 번째 내용</text>
|
|
31
|
+
</Accordion.Content>
|
|
32
|
+
</Accordion.Item>
|
|
33
|
+
<Accordion.Item value="second">
|
|
34
|
+
<Accordion.Header>
|
|
35
|
+
<Accordion.Trigger className="second-trigger" accessibility-label="두 번째">
|
|
36
|
+
<Accordion.Body>
|
|
37
|
+
<Accordion.Title>두 번째</Accordion.Title>
|
|
38
|
+
</Accordion.Body>
|
|
39
|
+
</Accordion.Trigger>
|
|
40
|
+
</Accordion.Header>
|
|
41
|
+
<Accordion.Content>
|
|
42
|
+
<text>두 번째 내용</text>
|
|
43
|
+
</Accordion.Content>
|
|
44
|
+
</Accordion.Item>
|
|
45
|
+
</Accordion.Root>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe("Accordion", () => {
|
|
50
|
+
it("opens and closes an item in uncontrolled mode", () => {
|
|
51
|
+
render(<TestAccordion />);
|
|
52
|
+
|
|
53
|
+
const trigger = getRenderedRoot().querySelector<HTMLElement>(".first-trigger");
|
|
54
|
+
const pressedOverlay = trigger?.querySelector<HTMLElement>(".seed-accordion__pressedOverlay");
|
|
55
|
+
expect(trigger).not.toBeNull();
|
|
56
|
+
expect(pressedOverlay).not.toBeNull();
|
|
57
|
+
expect(pressedOverlay).toHaveAttribute("accessibility-elements-hidden", "true");
|
|
58
|
+
expect(trigger).toHaveAttribute("accessibility-value", "접힘");
|
|
59
|
+
|
|
60
|
+
fireEvent.tap(trigger as HTMLElement);
|
|
61
|
+
expect(trigger).toHaveAttribute("accessibility-value", "펼쳐짐");
|
|
62
|
+
|
|
63
|
+
fireEvent.tap(trigger as HTMLElement);
|
|
64
|
+
expect(trigger).toHaveAttribute("accessibility-value", "접힘");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("transitions content between zero and its measured height", () => {
|
|
68
|
+
render(<TestAccordion defaultValues={["first"]} />);
|
|
69
|
+
|
|
70
|
+
const root = getRenderedRoot();
|
|
71
|
+
const trigger = root.querySelector<HTMLElement>(".first-trigger");
|
|
72
|
+
const content = root.querySelector<HTMLElement>(".first-content");
|
|
73
|
+
const contentInner = content?.querySelector<HTMLElement>(".seed-accordion__contentInner");
|
|
74
|
+
|
|
75
|
+
expect(content).not.toBeNull();
|
|
76
|
+
expect(contentInner).not.toBeNull();
|
|
77
|
+
expect(content).toHaveStyle({ height: "0px" });
|
|
78
|
+
|
|
79
|
+
act(() => {
|
|
80
|
+
fireEvent.layoutchange(contentInner as HTMLElement, { height: 84 });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(content).toHaveStyle({ height: "84px" });
|
|
84
|
+
|
|
85
|
+
fireEvent.tap(trigger as HTMLElement);
|
|
86
|
+
expect(content).toHaveStyle({ height: "0px" });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("keeps one item open by default and supports multiple mode", () => {
|
|
90
|
+
render(<TestAccordion multiple defaultValues={["first"]} />);
|
|
91
|
+
|
|
92
|
+
const root = getRenderedRoot();
|
|
93
|
+
const first = root.querySelector<HTMLElement>(".first-trigger");
|
|
94
|
+
const second = root.querySelector<HTMLElement>(".second-trigger");
|
|
95
|
+
|
|
96
|
+
expect(first).toHaveAttribute("accessibility-value", "펼쳐짐");
|
|
97
|
+
expect(second).toHaveAttribute("accessibility-value", "접힘");
|
|
98
|
+
|
|
99
|
+
fireEvent.tap(second as HTMLElement);
|
|
100
|
+
expect(first).toHaveAttribute("accessibility-value", "펼쳐짐");
|
|
101
|
+
expect(second).toHaveAttribute("accessibility-value", "펼쳐짐");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("reports controlled value changes without mutating the rendered state", () => {
|
|
105
|
+
const onValuesChange = vi.fn();
|
|
106
|
+
render(<TestAccordion values={[]} onValuesChange={onValuesChange} />);
|
|
107
|
+
|
|
108
|
+
const trigger = getRenderedRoot().querySelector<HTMLElement>(".first-trigger");
|
|
109
|
+
fireEvent.tap(trigger as HTMLElement);
|
|
110
|
+
|
|
111
|
+
expect(onValuesChange).toHaveBeenCalledWith(["first"]);
|
|
112
|
+
expect(trigger).toHaveAttribute("accessibility-value", "접힘");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("ignores tap when the root is disabled", () => {
|
|
116
|
+
const onValuesChange = vi.fn();
|
|
117
|
+
render(<TestAccordion disabled onValuesChange={onValuesChange} />);
|
|
118
|
+
|
|
119
|
+
const trigger = getRenderedRoot().querySelector<HTMLElement>(".first-trigger");
|
|
120
|
+
fireEvent.tap(trigger as HTMLElement);
|
|
121
|
+
|
|
122
|
+
expect(onValuesChange).not.toHaveBeenCalled();
|
|
123
|
+
expect(trigger).toHaveAttribute("accessibility-traits", "disabled");
|
|
124
|
+
expect(getRenderedRoot().querySelector(".first-content")).toHaveAttribute(
|
|
125
|
+
"accessibility-elements-hidden",
|
|
126
|
+
"true",
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
});
|