@toife/vue 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -1
- package/package.json +7 -7
- package/src/components/action/action.md +115 -0
- package/src/components/action/action.scss +1 -2
- package/src/components/action/action.vue +9 -21
- package/src/components/app/app.md +77 -0
- package/src/components/app/app.scss +3 -3
- package/src/components/app/app.vue +1 -1
- package/src/components/avatar/avatar.md +64 -0
- package/src/components/avatar/avatar.scss +2 -2
- package/src/components/avatar/avatar.vue +1 -1
- package/src/components/button/button.md +66 -0
- package/src/components/button/button.scss +13 -13
- package/src/components/button/button.vue +6 -11
- package/src/components/cable/cable.md +57 -0
- package/src/components/cable/cable.vue +1 -1
- package/src/components/card/card/card.md +57 -0
- package/src/components/card/card/card.scss +3 -3
- package/src/components/card/card/card.vue +1 -1
- package/src/components/card/card-body/card-body.md +34 -0
- package/src/components/card/card-body/card-body.scss +3 -3
- package/src/components/card/card-body/card-body.vue +3 -8
- package/src/components/card/card-footer/card-footer.md +42 -0
- package/src/components/card/card-footer/card-footer.scss +4 -4
- package/src/components/card/card-footer/card-footer.vue +2 -5
- package/src/components/card/card-header/card-header.md +44 -0
- package/src/components/card/card-header/card-header.scss +4 -4
- package/src/components/card/card-header/card-header.vue +2 -5
- package/src/components/checkbox/checkbox.md +60 -0
- package/src/components/checkbox/checkbox.scss +8 -8
- package/src/components/checkbox/checkbox.vue +11 -24
- package/src/components/collapse/collapse.md +59 -0
- package/src/components/collapse/collapse.scss +2 -2
- package/src/components/collapse/collapse.vue +1 -1
- package/src/components/container/container.md +38 -0
- package/src/components/container/container.vue +3 -8
- package/src/components/decision-modal/decision-modal.md +79 -0
- package/src/components/decision-modal/decision-modal.scss +3 -3
- package/src/components/decision-modal/decision-modal.vue +1 -1
- package/src/components/divider/divider.md +42 -0
- package/src/components/divider/divider.scss +1 -1
- package/src/components/divider/divider.vue +3 -6
- package/src/components/field/field.md +68 -0
- package/src/components/field/outline/outline-field.md +44 -0
- package/src/components/field/outline/outline.scss +8 -8
- package/src/components/field/outline/outline.vue +2 -2
- package/src/components/form-group/form-group.md +41 -0
- package/src/components/gesture-indicator/gesture-indicator.md +42 -0
- package/src/components/gesture-indicator/gesture-indicator.scss +2 -2
- package/src/components/gesture-indicator/gesture-indicator.vue +3 -6
- package/src/components/image/image.md +41 -0
- package/src/components/modal/modal.md +65 -0
- package/src/components/modal/modal.scss +2 -2
- package/src/components/modal/modal.vue +1 -1
- package/src/components/page/page.md +39 -0
- package/src/components/page/page.vue +3 -8
- package/src/components/present/present.md +60 -0
- package/src/components/present/present.vue +1 -1
- package/src/components/radio/radio/radio.md +53 -0
- package/src/components/radio/radio/radio.scss +8 -8
- package/src/components/radio/radio/radio.vue +7 -11
- package/src/components/radio/radio-group/radio-group.md +62 -0
- package/src/components/radio/radio-group/radio-group.vue +1 -6
- package/src/components/refresher/refresher.md +53 -0
- package/src/components/route/route-navigator/route-navigator.md +50 -0
- package/src/components/route/route-navigator/route-navigator.scss +1 -1
- package/src/components/route/route-navigator/route-navigator.vue +14 -9
- package/src/components/route/route-outlet/route-outlet.md +30 -0
- package/src/components/route/route-provider/route-provider.md +46 -0
- package/src/components/route/route-wrapper/route-wrapper.composable.ts +29 -14
- package/src/components/route/route-wrapper/route-wrapper.md +45 -0
- package/src/components/route/route-wrapper/route-wrapper.type.ts +4 -0
- package/src/components/route/route-wrapper/route-wrapper.vue +13 -5
- package/src/components/route/route.type.ts +1 -0
- package/src/components/segmented-field/segmented-field.md +58 -0
- package/src/components/segmented-field/segmented-field.scss +3 -3
- package/src/components/segmented-field/segmented-field.vue +20 -26
- package/src/components/skeleton/skeleton.md +47 -0
- package/src/components/skeleton/skeleton.scss +3 -3
- package/src/components/skeleton/skeleton.vue +1 -1
- package/src/components/switch/switch.md +57 -0
- package/src/components/switch/switch.scss +8 -8
- package/src/components/switch/switch.vue +9 -20
- package/src/components/tabs/tab/tab.md +52 -0
- package/src/components/tabs/tabs/tabs.md +59 -0
- package/src/components/tabs/tabs/tabs.scss +4 -6
- package/src/components/tabs/tabs/tabs.vue +4 -6
- package/src/components/toast/toast/toast.md +56 -0
- package/src/components/toast/toast-content/toast-content.md +41 -0
- package/src/components/toast/toast-content/toast-content.scss +4 -4
- package/src/components/toast/toast-content/toast-content.vue +5 -11
- package/src/components/toolbar/toolbar.md +57 -0
- package/src/components/toolbar/toolbar.scss +2 -2
- package/src/components/toolbar/toolbar.vue +5 -11
- package/src/factory.ts +2 -0
- package/src/utils/element.md +33 -0
- package/src/utils/events.md +29 -0
- package/src/utils/style.md +49 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# `Present` _(named export; not in default `createToife`)_
|
|
2
|
+
|
|
3
|
+
> **Not** registered by `createToife()` — import: `import { Present } from "@toife/vue"` and register globally yourself if needed.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Overlay layer: backdrop + animated panel, stacking z-index via `usePresent`. Used internally by `Modal`, `Action`, `DecisionModal`.
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ----- | ----- |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| Other | None. |
|
|
15
|
+
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<Present :visible="show" placement="bottom" backdrop="display" @close="onClose">
|
|
20
|
+
<div>Content</div>
|
|
21
|
+
</Present>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Description |
|
|
27
|
+
| ----------------- | -------------------------------------- | ----------- | ----------------------------------- |
|
|
28
|
+
| `visible` | `boolean` | `false` | Open/close (with `duration` delay). |
|
|
29
|
+
| `backdrop` | `"display" \| "none" \| "transparent"` | `"display"` | Backdrop. |
|
|
30
|
+
| `placement` | `PresentPlacement` | `"bottom"` | Animation direction. |
|
|
31
|
+
| `keepalive` | `boolean` | `false` | Keep DOM when closed. |
|
|
32
|
+
| `duration` | `number` | `200` | ms. |
|
|
33
|
+
| `bounce` | `number \| string \| boolean` | `false` | Open bounce. |
|
|
34
|
+
| `class` / `style` | `unknown` | — | Panel. |
|
|
35
|
+
|
|
36
|
+
**Type source:** `src/components/present/present.type.ts`
|
|
37
|
+
|
|
38
|
+
## Events (emits)
|
|
39
|
+
|
|
40
|
+
| Event | Payload | Description |
|
|
41
|
+
| ------- | --------------- | ------------------------------------------- |
|
|
42
|
+
| `close` | `type?: string` | e.g. `'backdrop'` when backdrop is clicked. |
|
|
43
|
+
|
|
44
|
+
## Slots
|
|
45
|
+
|
|
46
|
+
| Slot | Description |
|
|
47
|
+
| --------- | -------------- |
|
|
48
|
+
| `default` | Panel content. |
|
|
49
|
+
|
|
50
|
+
## Expose (template ref)
|
|
51
|
+
|
|
52
|
+
| API | Description |
|
|
53
|
+
| -------------------------------- | ------------------------------------------------- |
|
|
54
|
+
| `render(options: RenderOptions)` | Update transition styles (translate, opacity, …). |
|
|
55
|
+
| `open()` / `close()` | Manual animation control. |
|
|
56
|
+
|
|
57
|
+
## See also
|
|
58
|
+
|
|
59
|
+
- Source: `src/components/present`
|
|
60
|
+
- `present.composable.ts` — `usePresent` (z-index stack)
|
|
@@ -51,7 +51,7 @@ const backdropAttrs = computed(() => {
|
|
|
51
51
|
// Present attributes
|
|
52
52
|
const presentAttrs = computed(() => {
|
|
53
53
|
return {
|
|
54
|
-
class: [withPrefix(
|
|
54
|
+
class: [withPrefix("present"), props.class, props.placement],
|
|
55
55
|
style: [
|
|
56
56
|
{
|
|
57
57
|
zIndex: zIndex.value,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# `<t-radio>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Single choice in a group — **must** be used inside `t-radio-group` so selection updates via inject.
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ----- | -------------------------------- |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| Other | Parent `t-radio-group` required. |
|
|
15
|
+
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<t-radio-group v-model="x">
|
|
20
|
+
<t-radio value="1">One</t-radio>
|
|
21
|
+
</t-radio-group>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Description |
|
|
27
|
+
| ---------- | ------------------ | ------------ | ------------------------- |
|
|
28
|
+
| `value` | `string \| number` | _(required)_ | Value when selected. |
|
|
29
|
+
| `role` | `string` | — | Overrides group/app role. |
|
|
30
|
+
| `variant` | `RadioVariant` | — | Overrides group variant. |
|
|
31
|
+
| `disabled` | `boolean` | `false` | Or from group. |
|
|
32
|
+
| `readonly` | `boolean` | `false` | Or from group. |
|
|
33
|
+
| `shadow` | `boolean` | — | Group/app default. |
|
|
34
|
+
|
|
35
|
+
**Type source:** `src/components/radio/radio/radio.type.ts`
|
|
36
|
+
|
|
37
|
+
## Events (emits)
|
|
38
|
+
|
|
39
|
+
_None_ — selection goes through the group’s `setValue`.
|
|
40
|
+
|
|
41
|
+
## Slots
|
|
42
|
+
|
|
43
|
+
| Slot | Description |
|
|
44
|
+
| --------- | ----------- |
|
|
45
|
+
| `default` | Label. |
|
|
46
|
+
|
|
47
|
+
## Accessibility (a11y)
|
|
48
|
+
|
|
49
|
+
`tabindex` 0/-1; Space/Enter selects. Consider `role="radiogroup"` on the container in your app if needed.
|
|
50
|
+
|
|
51
|
+
## See also
|
|
52
|
+
|
|
53
|
+
- Source: `src/components/radio/radio`
|
|
@@ -5,14 +5,14 @@ $radio: sass.fn-naming-prefix("radio");
|
|
|
5
5
|
$radio-icon: sass.fn-naming-prefix("radio-icon");
|
|
6
6
|
|
|
7
7
|
// Properties - layer: item
|
|
8
|
-
$background-color: sass.fn-naming-var("
|
|
9
|
-
$background-color-hover: sass.fn-naming-var("
|
|
10
|
-
$background-color-inactive: sass.fn-naming-var("
|
|
11
|
-
$background-color-contrast: sass.fn-naming-var("
|
|
12
|
-
$background-color-disabled: sass.fn-naming-var("
|
|
13
|
-
|
|
14
|
-
$border-color: sass.fn-naming-var("
|
|
15
|
-
$border-color-inactive: sass.fn-naming-var("
|
|
8
|
+
$background-color: sass.fn-naming-var("radio", "background-color");
|
|
9
|
+
$background-color-hover: sass.fn-naming-var("radio", "background-color", "subtle");
|
|
10
|
+
$background-color-inactive: sass.fn-naming-var("radio", "background-color", "soft");
|
|
11
|
+
$background-color-contrast: sass.fn-naming-var("radio", "background-color", "contrast");
|
|
12
|
+
$background-color-disabled: sass.fn-naming-var("radio", "background-color", "subtle");
|
|
13
|
+
|
|
14
|
+
$border-color: sass.fn-naming-var("radio", "border-color");
|
|
15
|
+
$border-color-inactive: sass.fn-naming-var("radio", "border-color", "subtle");
|
|
16
16
|
|
|
17
17
|
$transition-duration: sass.fn-naming-var("motion", "duration");
|
|
18
18
|
$border-radius: sass.fn-naming-var("border-radius");
|
|
@@ -45,14 +45,12 @@ const isChecked = computed(() => {
|
|
|
45
45
|
return radioGroupState?.modelValue.value === props.value;
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
const shadow = computed(() => {
|
|
49
|
-
return (props?.shadow !== undefined ? props.shadow : radioGroupState?.shadow.value) ?? false;
|
|
50
|
-
});
|
|
51
|
-
|
|
52
48
|
const radioAttrs = computed(() => {
|
|
49
|
+
const shadow =
|
|
50
|
+
(props?.shadow !== undefined ? props.shadow : radioGroupState?.shadow.value) ?? false;
|
|
53
51
|
return {
|
|
54
52
|
class: [
|
|
55
|
-
withPrefix(["layer", "
|
|
53
|
+
withPrefix(["layer", "radio"]),
|
|
56
54
|
withPrefix([
|
|
57
55
|
"role",
|
|
58
56
|
(isChecked.value && !disabled.value
|
|
@@ -65,18 +63,16 @@ const radioAttrs = computed(() => {
|
|
|
65
63
|
on: isChecked.value,
|
|
66
64
|
disabled: disabled.value,
|
|
67
65
|
readonly: readonly.value,
|
|
68
|
-
shadow
|
|
66
|
+
shadow,
|
|
69
67
|
focus: isFocused.value,
|
|
70
68
|
},
|
|
71
69
|
],
|
|
72
70
|
};
|
|
73
71
|
});
|
|
74
72
|
|
|
75
|
-
const radioIconAttrs =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
};
|
|
79
|
-
});
|
|
73
|
+
const radioIconAttrs = {
|
|
74
|
+
class: [withPrefix("radio-icon")],
|
|
75
|
+
} as const;
|
|
80
76
|
|
|
81
77
|
/// Methods
|
|
82
78
|
/// ------------------------------------------------------------
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `<t-radio-group>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Radio group with shared `v-model`; provides variant/readonly/disabled/shadow to child `t-radio` via provide/inject.
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ----- | ------------------------------------ |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| Other | Wrap one or more `t-radio` children. |
|
|
15
|
+
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<t-radio-group v-model="choice" orientation="vertical">
|
|
20
|
+
<t-radio value="a">A</t-radio>
|
|
21
|
+
<t-radio value="b">B</t-radio>
|
|
22
|
+
</t-radio-group>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Props
|
|
26
|
+
|
|
27
|
+
| Prop | Type | Default | Description |
|
|
28
|
+
| ------------- | ---------------------------- | ------------ | ------------------------------------- |
|
|
29
|
+
| `modelValue` | `string \| number` | — | Selected value (`v-model`). |
|
|
30
|
+
| `role` | `string` | — | Theme; default from app. |
|
|
31
|
+
| `variant` | `RadioVariant` | `"fill"` | Default for radios unless overridden. |
|
|
32
|
+
| `disabled` | `boolean` | `false` | Whole group. |
|
|
33
|
+
| `readonly` | `boolean` | `false` | |
|
|
34
|
+
| `shadow` | `boolean` | — | Default from app. |
|
|
35
|
+
| `orientation` | `"horizontal" \| "vertical"` | `"vertical"` | Flex layout. |
|
|
36
|
+
|
|
37
|
+
**Type source:** `src/components/radio/radio-group/radio-group.type.ts`
|
|
38
|
+
|
|
39
|
+
## Events (emits)
|
|
40
|
+
|
|
41
|
+
| Event | Payload | Description |
|
|
42
|
+
| ------------------- | ------------------ | ------------------------------- |
|
|
43
|
+
| `update:modelValue` | `string \| number` | When a child radio is selected. |
|
|
44
|
+
|
|
45
|
+
## Slots
|
|
46
|
+
|
|
47
|
+
| Slot | Description |
|
|
48
|
+
| --------- | ------------------- |
|
|
49
|
+
| `default` | `t-radio` children. |
|
|
50
|
+
|
|
51
|
+
## `v-model`
|
|
52
|
+
|
|
53
|
+
`modelValue` / `update:modelValue`.
|
|
54
|
+
|
|
55
|
+
## Provide / inject
|
|
56
|
+
|
|
57
|
+
`RADIO_GROUP_PROVIDER_STATE_KEY`: `modelValue`, `role`, `variant`, `disabled`, `readonly`, `shadow`, `setValue`.
|
|
58
|
+
|
|
59
|
+
## See also
|
|
60
|
+
|
|
61
|
+
- Source: `src/components/radio/radio-group`
|
|
62
|
+
- [radio.md](../radio/radio.md)
|
|
@@ -37,12 +37,7 @@ const shadow = computed(() => {
|
|
|
37
37
|
|
|
38
38
|
const radioGroupAttrs = computed(() => {
|
|
39
39
|
return {
|
|
40
|
-
class: [
|
|
41
|
-
withPrefix(["layer", "item"]),
|
|
42
|
-
withPrefix(["role", role.value]),
|
|
43
|
-
withPrefix("radio-group"),
|
|
44
|
-
props.orientation,
|
|
45
|
-
],
|
|
40
|
+
class: [withPrefix("radio-group"), props.orientation],
|
|
46
41
|
};
|
|
47
42
|
});
|
|
48
43
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# `<t-refresher>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Pull-to-refresh using `@toife/gesture` on the scroll container; two variants control when refresh fires (`max` vs `up`).
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ----- | ----------------- |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| Other | `@toife/gesture`. |
|
|
15
|
+
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<t-refresher variant="up" :threshold="120" @refresh="(done) => load().finally(done)">
|
|
20
|
+
<template #icon="{ offset, refreshing }">…</template>
|
|
21
|
+
<div class="scroll-area">…</div>
|
|
22
|
+
</t-refresher>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Props
|
|
26
|
+
|
|
27
|
+
| Prop | Type | Default | Description |
|
|
28
|
+
| ----------- | --------------- | ------- | ---------------------------------------------------------------------------------------- |
|
|
29
|
+
| `threshold` | `number` | `120` | Pull threshold (px) depending on `variant`. |
|
|
30
|
+
| `variant` | `"max" \| "up"` | `"max"` | `max`: fire during `move` when threshold reached; `up`: fire on `up` when threshold met. |
|
|
31
|
+
| `offset` | `number` | — | Override displayed offset (default `moveOffset / 2`). |
|
|
32
|
+
|
|
33
|
+
**Type source:** `src/components/refresher/refresher.type.ts`
|
|
34
|
+
|
|
35
|
+
## Events (emits)
|
|
36
|
+
|
|
37
|
+
| Event | Payload | Description |
|
|
38
|
+
| --------- | ------------------- | ------------------------------------------------- |
|
|
39
|
+
| `refresh` | `close: () => void` | Call `close()` when refresh finishes to reset UI. |
|
|
40
|
+
| `move` | `offset: number` | While pulling. |
|
|
41
|
+
| `cancel` | — | Pull cancelled. |
|
|
42
|
+
| `start` | — | Gesture started. |
|
|
43
|
+
|
|
44
|
+
## Slots
|
|
45
|
+
|
|
46
|
+
| Slot | Slot props | Description |
|
|
47
|
+
| --------- | ------------------------ | ----------------------------------------- |
|
|
48
|
+
| `icon` | `{ offset, refreshing }` | Indicator above the scroll area. |
|
|
49
|
+
| `default` | — | Scroll region (internal ref for gesture). |
|
|
50
|
+
|
|
51
|
+
## See also
|
|
52
|
+
|
|
53
|
+
- Source: `src/components/refresher`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `<t-route-navigator>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Displays a stack of screens with transitions and optional edge swipe to `router.back()` when `variant="swipe"`. Listens to `stack` from `RouteProvider`.
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ------------ | ------------------------------------------------------------------------ |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| `vue-router` | **Required** |
|
|
15
|
+
| Other | `@toife/gesture`; `RouteProvider` ancestor (usually via `RouteWrapper`). |
|
|
16
|
+
|
|
17
|
+
## Basic usage
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<t-route-wrapper>
|
|
21
|
+
<t-route-navigator variant="swipe" direction="right" />
|
|
22
|
+
</t-route-wrapper>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Props
|
|
26
|
+
|
|
27
|
+
| Prop | Type | Default | Description |
|
|
28
|
+
| ----------- | ------------------- | --------- | ----------------------------------------- |
|
|
29
|
+
| `direction` | `"left" \| "right"` | `"right"` | Gesture / animation direction. |
|
|
30
|
+
| `variant` | `"none" \| "swipe"` | `"none"` | Enables swipe navigation when not `none`. |
|
|
31
|
+
| `keepalive` | `boolean` | `false` | Reserved for stack/DOM retention. |
|
|
32
|
+
|
|
33
|
+
**Type source:** `src/components/route/route-navigator/route-navigator.type.ts`
|
|
34
|
+
|
|
35
|
+
## Events (emits)
|
|
36
|
+
|
|
37
|
+
_None._
|
|
38
|
+
|
|
39
|
+
## Slots
|
|
40
|
+
|
|
41
|
+
_None_ — fixed structure: stack loop → `RouteProvider` + `RouteOutlet`.
|
|
42
|
+
|
|
43
|
+
## Special behavior
|
|
44
|
+
|
|
45
|
+
- Swipe along `direction`: preview transform; release past ~60% width → `goBack()`.
|
|
46
|
+
- `fast` swipe calls `router.back()`.
|
|
47
|
+
|
|
48
|
+
## See also
|
|
49
|
+
|
|
50
|
+
- Source: `src/components/route/route-navigator`
|
|
@@ -6,7 +6,7 @@ $navigator-component: sass.fn-naming-prefix("route-navigator-component");
|
|
|
6
6
|
$navigator-backdrop: sass.fn-naming-prefix("route-navigator-backdrop");
|
|
7
7
|
|
|
8
8
|
// Property name
|
|
9
|
-
$background-color: sass.fn-naming-var("
|
|
9
|
+
$background-color: sass.fn-naming-var("app", "background-color");
|
|
10
10
|
$transition-duration: sass.fn-naming-dvar(
|
|
11
11
|
("route-navigator-transition-duration"),
|
|
12
12
|
sass.fn-naming-var("motion", "duration")
|
|
@@ -16,6 +16,12 @@ import type { RouteStack } from "../route.type";
|
|
|
16
16
|
import { useRouter } from "vue-router";
|
|
17
17
|
import { clone } from "../route.util";
|
|
18
18
|
|
|
19
|
+
// Max translate offset (%) for the layer behind the active page during swipe.
|
|
20
|
+
// Active uses 0–100%; back uses (peek)*(100−percent)/100, so a peek of 40 makes the
|
|
21
|
+
// back layer move 2.5× slower than the active layer (parallax). Use 100 for 1:1 motion
|
|
22
|
+
// (no edge peek at rest: back starts at -100%).
|
|
23
|
+
const BACK_LAYER_PEEK_PCT = 40;
|
|
24
|
+
|
|
19
25
|
/// Define
|
|
20
26
|
/// ------------------------------------------------------------
|
|
21
27
|
const props = withDefaults(defineProps<RouteNavigatorProps>(), {
|
|
@@ -30,7 +36,7 @@ const router = useRouter();
|
|
|
30
36
|
const navigatorRef = ref<HTMLElement>();
|
|
31
37
|
const ges = ref<unknown>(null);
|
|
32
38
|
const transform = reactive({
|
|
33
|
-
back:
|
|
39
|
+
back: BACK_LAYER_PEEK_PCT,
|
|
34
40
|
prepare: 100,
|
|
35
41
|
active: 0,
|
|
36
42
|
backdrop: 0,
|
|
@@ -131,16 +137,18 @@ const changeRoute = (value: RouteStack[]) => {
|
|
|
131
137
|
};
|
|
132
138
|
|
|
133
139
|
const goBack = () => {
|
|
134
|
-
|
|
140
|
+
const url = stack.value[activeIndex.value - 1].fullPath;
|
|
141
|
+
router.push(url);
|
|
135
142
|
};
|
|
136
143
|
|
|
137
144
|
const resetTransform = () => {
|
|
138
|
-
transform.back =
|
|
145
|
+
transform.back = BACK_LAYER_PEEK_PCT;
|
|
139
146
|
transform.prepare = 100;
|
|
140
147
|
transform.active = 0;
|
|
141
148
|
};
|
|
142
149
|
|
|
143
150
|
const move = (data: RouteNavigatorGesture) => {
|
|
151
|
+
console.log(stack.value);
|
|
144
152
|
const width = navigatorRef.value?.offsetWidth ?? 0;
|
|
145
153
|
let percent = 0;
|
|
146
154
|
|
|
@@ -150,8 +158,8 @@ const move = (data: RouteNavigatorGesture) => {
|
|
|
150
158
|
percent = (Math.abs(data.deltaY) / width) * 100;
|
|
151
159
|
}
|
|
152
160
|
|
|
153
|
-
transform.back =
|
|
154
|
-
transform.active =
|
|
161
|
+
transform.back = ((100 - percent) * BACK_LAYER_PEEK_PCT) / 100;
|
|
162
|
+
transform.active = percent;
|
|
155
163
|
transform.backdrop = 100 - transform.active;
|
|
156
164
|
};
|
|
157
165
|
|
|
@@ -191,8 +199,7 @@ onMounted(() => {
|
|
|
191
199
|
beforeEvent(e: Event) {
|
|
192
200
|
const target = e.target as HTMLElement | null;
|
|
193
201
|
const isEditable = target?.closest("input, textarea, select, button, [contenteditable]");
|
|
194
|
-
if (isEditable) return false;
|
|
195
|
-
e.preventDefault();
|
|
202
|
+
if (isEditable || props.variant === "none") return false;
|
|
196
203
|
e.stopPropagation();
|
|
197
204
|
return prevPage.value;
|
|
198
205
|
},
|
|
@@ -216,7 +223,6 @@ onMounted(() => {
|
|
|
216
223
|
event: Event;
|
|
217
224
|
}) {
|
|
218
225
|
if (initialDirection !== props.direction) return;
|
|
219
|
-
event.stopPropagation();
|
|
220
226
|
event.preventDefault();
|
|
221
227
|
move({ deltaX, deltaY });
|
|
222
228
|
},
|
|
@@ -233,7 +239,6 @@ onMounted(() => {
|
|
|
233
239
|
event: Event;
|
|
234
240
|
}) {
|
|
235
241
|
if (initialDirection !== props.direction) return;
|
|
236
|
-
event.stopPropagation();
|
|
237
242
|
event.preventDefault();
|
|
238
243
|
up({ deltaX, deltaY });
|
|
239
244
|
},
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# `<t-route-outlet>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Resolves and renders a route component (sync or async dynamic import).
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ----- | ------------------------------------------------------------- |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| Other | Used inside `RouteNavigator` with `component` from the stack. |
|
|
15
|
+
|
|
16
|
+
## Props
|
|
17
|
+
|
|
18
|
+
| Prop | Type | Description |
|
|
19
|
+
| ----------- | --------- | ---------------------------------------------------------- |
|
|
20
|
+
| `component` | `unknown` | Route component (may be `{ default: () => import(...) }`). |
|
|
21
|
+
|
|
22
|
+
_(Inline type in `route-outlet.vue`.)_
|
|
23
|
+
|
|
24
|
+
## Slots
|
|
25
|
+
|
|
26
|
+
_None_ — renders `<component :is="…">`.
|
|
27
|
+
|
|
28
|
+
## See also
|
|
29
|
+
|
|
30
|
+
- Source: `src/components/route/route-outlet`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# `<t-route-provider>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Provides `stack` (`RouteStack[]`) to `RouteNavigator` / children via inject.
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ----- | ------------------------------------------------------ |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| Other | Usually created by `RouteWrapper` or `RouteNavigator`. |
|
|
15
|
+
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<!-- Rarely used directly; RouteNavigator wraps children -->
|
|
20
|
+
<t-route-provider :stack="myStack">
|
|
21
|
+
<slot />
|
|
22
|
+
</t-route-provider>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Props
|
|
26
|
+
|
|
27
|
+
| Prop | Type | Description |
|
|
28
|
+
| ------- | -------------- | ---------------------------------- |
|
|
29
|
+
| `stack` | `RouteStack[]` | Route stack (see `route.type.ts`). |
|
|
30
|
+
|
|
31
|
+
**Type source:** `src/components/route/route-provider/route-provider.type.ts`
|
|
32
|
+
|
|
33
|
+
## Slots
|
|
34
|
+
|
|
35
|
+
| Slot | Description |
|
|
36
|
+
| --------- | ------------------------------------- |
|
|
37
|
+
| `default` | Children (often outlet or navigator). |
|
|
38
|
+
|
|
39
|
+
## Provide / inject
|
|
40
|
+
|
|
41
|
+
`ROUTE_PROVIDER_STATE_KEY` → `{ stack }` (computed).
|
|
42
|
+
|
|
43
|
+
## See also
|
|
44
|
+
|
|
45
|
+
- Source: `src/components/route/route-provider`
|
|
46
|
+
- `src/components/route/route.type.ts`
|
|
@@ -1,39 +1,54 @@
|
|
|
1
1
|
import { shallowRef } from "vue";
|
|
2
2
|
import { type RouteComponent, type RouteLocationMatched } from "vue-router";
|
|
3
3
|
import { type RouteStack } from "../route.type";
|
|
4
|
+
import { RouteWrapperOption } from "./route-wrapper.type";
|
|
4
5
|
|
|
5
6
|
const stack = shallowRef<RouteStack[]>([]);
|
|
6
|
-
const buildTree = (matched: RouteLocationMatched[], data: RouteStack[]) => {
|
|
7
|
-
if (matched.length === 0) return data;
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const buildTree = (
|
|
9
|
+
matched: RouteLocationMatched[],
|
|
10
|
+
current: RouteStack[],
|
|
11
|
+
option: RouteWrapperOption
|
|
12
|
+
) => {
|
|
13
|
+
if (matched.length === 0) return current;
|
|
14
|
+
|
|
15
|
+
// Case current is previous
|
|
16
|
+
if (current.length > 1 && current[current.length - 2]?.name === matched[0].name) {
|
|
17
|
+
current.pop();
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
// Case
|
|
15
|
-
if (
|
|
20
|
+
// Case current is current
|
|
21
|
+
if (
|
|
22
|
+
current.length > 0 &&
|
|
23
|
+
current[current.length - 1] &&
|
|
24
|
+
current[current.length - 1].name === matched[0].name
|
|
25
|
+
) {
|
|
16
26
|
matched.shift();
|
|
17
|
-
|
|
27
|
+
current[current.length - 1].stack = buildTree(
|
|
28
|
+
matched,
|
|
29
|
+
current[current.length - 1].stack,
|
|
30
|
+
option
|
|
31
|
+
);
|
|
18
32
|
}
|
|
19
|
-
// Case
|
|
33
|
+
// Case current is add
|
|
20
34
|
else {
|
|
21
35
|
const name = String(matched[0].name);
|
|
22
36
|
const component = matched[0].components as RouteComponent;
|
|
23
37
|
matched.shift();
|
|
24
|
-
|
|
38
|
+
current.push({
|
|
25
39
|
name,
|
|
26
40
|
component,
|
|
27
|
-
|
|
41
|
+
fullPath: option.fullPath,
|
|
42
|
+
stack: buildTree(matched, [], option),
|
|
28
43
|
});
|
|
29
44
|
}
|
|
30
45
|
|
|
31
|
-
return
|
|
46
|
+
return current;
|
|
32
47
|
};
|
|
33
48
|
|
|
34
49
|
export const useRouteWrapper = () => {
|
|
35
|
-
const updateRoutes = (matched: RouteLocationMatched[]) => {
|
|
36
|
-
stack.value = buildTree([...matched], [...stack.value]);
|
|
50
|
+
const updateRoutes = (matched: RouteLocationMatched[], option: RouteWrapperOption) => {
|
|
51
|
+
stack.value = buildTree([...matched], [...stack.value], option);
|
|
37
52
|
};
|
|
38
53
|
|
|
39
54
|
return {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# `<t-route-wrapper>`
|
|
2
|
+
|
|
3
|
+
> Default prefix is `t-` — change via `createToife({ prefix: "..." })`.
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Syncs the route stack with `vue-router` and wraps content in `RouteProvider` — main entry for stack-based navigation (with `RouteNavigator`).
|
|
8
|
+
|
|
9
|
+
## Requirements / dependencies
|
|
10
|
+
|
|
11
|
+
| Item | Notes |
|
|
12
|
+
| ------------ | ---------------------------------------- |
|
|
13
|
+
| Vue | ^3.5 |
|
|
14
|
+
| `vue-router` | **Required** — `useRoute` / `useRouter`. |
|
|
15
|
+
|
|
16
|
+
## Basic usage
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<t-route-wrapper home-route-name="home">
|
|
20
|
+
<t-route-navigator />
|
|
21
|
+
</t-route-wrapper>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Description |
|
|
27
|
+
| --------------- | -------- | -------- | ---------------------------------------------- |
|
|
28
|
+
| `homeRouteName` | `string` | `"home"` | Name of the root route used to seed the stack. |
|
|
29
|
+
|
|
30
|
+
**Type source:** `src/components/route/route-wrapper/route-wrapper.type.ts`
|
|
31
|
+
|
|
32
|
+
## Slots
|
|
33
|
+
|
|
34
|
+
| Slot | Description |
|
|
35
|
+
| --------- | ---------------------------------- |
|
|
36
|
+
| `default` | Child tree (navigator, layout, …). |
|
|
37
|
+
|
|
38
|
+
## Provide / inject
|
|
39
|
+
|
|
40
|
+
Renders `RouteProvider` with `stack` from `useRouteWrapper`.
|
|
41
|
+
|
|
42
|
+
## See also
|
|
43
|
+
|
|
44
|
+
- Source: `src/components/route/route-wrapper`
|
|
45
|
+
- [route-provider.md](../route-provider/route-provider.md), [route-navigator.md](../route-navigator/route-navigator.md)
|