@lt-three/love3 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +86 -2
- package/dist/native/analytics/animation.d.ts +4 -0
- package/dist/native/analytics/animation.js +6 -0
- package/dist/native/analytics/chart.types.d.ts +25 -0
- package/dist/native/analytics/chart.types.js +0 -0
- package/dist/native/analytics/line-chart.d.ts +4 -0
- package/dist/native/analytics/line-chart.ios.d.ts +4 -0
- package/dist/native/analytics/line-chart.ios.js +24 -0
- package/dist/native/analytics/line-chart.js +33 -0
- package/dist/native/analytics/metric-card.d.ts +10 -0
- package/dist/native/analytics/metric-card.js +29 -0
- package/dist/native/analytics/multi-line-chart.d.ts +17 -0
- package/dist/native/analytics/multi-line-chart.js +215 -0
- package/dist/native/analytics/pie-chart.d.ts +15 -0
- package/dist/native/analytics/pie-chart.ios.d.ts +4 -0
- package/dist/native/analytics/pie-chart.ios.js +24 -0
- package/dist/native/analytics/pie-chart.js +92 -0
- package/dist/native/analytics/single-number.d.ts +19 -0
- package/dist/native/analytics/single-number.js +101 -0
- package/dist/native/atom/avatar.d.ts +21 -0
- package/dist/native/atom/avatar.js +46 -0
- package/dist/native/atom/badge.d.ts +28 -0
- package/dist/native/atom/badge.js +51 -0
- package/dist/native/atom/button.d.ts +46 -0
- package/dist/native/atom/button.js +109 -0
- package/dist/native/atom/checkbox.d.ts +21 -0
- package/dist/native/atom/checkbox.js +47 -0
- package/dist/native/atom/colored-value.d.ts +12 -0
- package/dist/native/atom/colored-value.js +24 -0
- package/dist/native/atom/image.d.ts +21 -0
- package/dist/native/atom/image.js +72 -0
- package/dist/native/atom/label.d.ts +18 -0
- package/dist/native/atom/label.js +33 -0
- package/dist/native/atom/link.d.ts +18 -0
- package/dist/native/atom/link.js +25 -0
- package/dist/native/atom/readout.d.ts +22 -0
- package/dist/native/atom/readout.js +39 -0
- package/dist/native/atom/search-input.d.ts +12 -0
- package/dist/native/atom/search-input.js +36 -0
- package/dist/native/atom/select.d.ts +54 -0
- package/dist/native/atom/select.js +200 -0
- package/dist/native/atom/separator.d.ts +13 -0
- package/dist/native/atom/separator.js +17 -0
- package/dist/native/atom/skeleton.d.ts +12 -0
- package/dist/native/atom/skeleton.js +39 -0
- package/dist/native/atom/slider.d.ts +32 -0
- package/dist/native/atom/slider.js +75 -0
- package/dist/native/atom/spinner.d.ts +15 -0
- package/dist/native/atom/spinner.js +25 -0
- package/dist/native/atom/switch.d.ts +18 -0
- package/dist/native/atom/switch.js +52 -0
- package/dist/native/atom/symbol.d.ts +16 -0
- package/dist/native/atom/symbol.js +38 -0
- package/dist/native/atom/symbol.types.d.ts +25 -0
- package/dist/native/atom/symbol.types.js +49 -0
- package/dist/native/atom/text-field.d.ts +49 -0
- package/dist/native/atom/text-field.js +56 -0
- package/dist/native/atom/text.d.ts +2 -0
- package/dist/native/atom/text.js +3 -0
- package/dist/native/atom/theme-toggle.d.ts +21 -0
- package/dist/native/atom/theme-toggle.js +36 -0
- package/dist/native/atom/timezone-select.d.ts +16 -0
- package/dist/native/atom/timezone-select.js +28 -0
- package/dist/native/atom/typography.d.ts +13 -0
- package/dist/native/atom/typography.js +28 -0
- package/dist/native/base/button.d.ts +61 -0
- package/dist/native/base/button.js +92 -0
- package/dist/native/base/form.d.ts +72 -0
- package/dist/native/base/form.js +113 -0
- package/dist/native/base/glass-card.d.ts +15 -0
- package/dist/native/base/glass-card.js +38 -0
- package/dist/native/base/input.d.ts +29 -0
- package/dist/native/base/input.js +27 -0
- package/dist/native/base/sheet.d.ts +71 -0
- package/dist/native/base/sheet.js +187 -0
- package/dist/native/base/text.d.ts +14 -0
- package/dist/native/base/text.js +53 -0
- package/dist/native/form/checkbox.d.ts +13 -0
- package/dist/native/form/checkbox.js +55 -0
- package/dist/native/form/date-picker.d.ts +23 -0
- package/dist/native/form/date-picker.js +119 -0
- package/dist/native/form/form.d.ts +23 -0
- package/dist/native/form/form.js +45 -0
- package/dist/native/form/radio-group.d.ts +23 -0
- package/dist/native/form/radio-group.js +88 -0
- package/dist/native/form/select.d.ts +13 -0
- package/dist/native/form/select.js +45 -0
- package/dist/native/form/slider.d.ts +14 -0
- package/dist/native/form/slider.js +42 -0
- package/dist/native/form/switch.d.ts +9 -0
- package/dist/native/form/switch.js +59 -0
- package/dist/native/form/text-area.d.ts +11 -0
- package/dist/native/form/text-area.js +50 -0
- package/dist/native/form/text-input.d.ts +18 -0
- package/dist/native/form/text-input.js +90 -0
- package/dist/native/index.d.ts +1 -0
- package/dist/native/index.js +0 -0
- package/dist/native/layout/accordion.d.ts +25 -0
- package/dist/native/layout/accordion.js +54 -0
- package/dist/native/layout/card.d.ts +47 -0
- package/dist/native/layout/card.js +57 -0
- package/dist/native/layout/description.d.ts +16 -0
- package/dist/native/layout/description.js +32 -0
- package/dist/native/layout/error.d.ts +21 -0
- package/dist/native/layout/error.js +44 -0
- package/dist/native/layout/information.d.ts +25 -0
- package/dist/native/layout/information.js +35 -0
- package/dist/native/layout/locked.d.ts +38 -0
- package/dist/native/layout/locked.js +94 -0
- package/dist/native/layout/modal.d.ts +25 -0
- package/dist/native/layout/modal.js +93 -0
- package/dist/native/layout/not-found.d.ts +17 -0
- package/dist/native/layout/not-found.js +30 -0
- package/dist/native/layout/page-frame.d.ts +23 -0
- package/dist/native/layout/page-frame.js +46 -0
- package/dist/native/layout/panel.d.ts +18 -0
- package/dist/native/layout/panel.js +23 -0
- package/dist/native/layout/reorderable-list.d.ts +42 -0
- package/dist/native/layout/reorderable-list.js +52 -0
- package/dist/native/layout/sheet.d.ts +30 -0
- package/dist/native/layout/sheet.js +46 -0
- package/dist/native/layout/simple-dialog.d.ts +16 -0
- package/dist/native/layout/simple-dialog.js +20 -0
- package/dist/native/layout/simple-table.d.ts +50 -0
- package/dist/native/layout/simple-table.js +75 -0
- package/dist/native/layout/tab-bar.d.ts +33 -0
- package/dist/native/layout/tab-bar.js +48 -0
- package/dist/native/layout/tabs.d.ts +28 -0
- package/dist/native/layout/tabs.js +54 -0
- package/dist/native/layout/tuning-panel.d.ts +24 -0
- package/dist/native/layout/tuning-panel.js +246 -0
- package/dist/native/lib/autocomplete.d.ts +7 -0
- package/dist/native/lib/autocomplete.js +34 -0
- package/dist/native/lib/breakpoints.d.ts +14 -0
- package/dist/native/lib/breakpoints.js +17 -0
- package/dist/native/lib/chart-palette.d.ts +8 -0
- package/dist/native/lib/chart-palette.js +20 -0
- package/dist/native/lib/confirm.d.ts +49 -0
- package/dist/native/lib/confirm.js +70 -0
- package/dist/native/lib/control.d.ts +24 -0
- package/dist/native/lib/control.js +0 -0
- package/dist/native/lib/external-store.d.ts +17 -0
- package/dist/native/lib/external-store.js +30 -0
- package/dist/native/lib/keyboard.d.ts +15 -0
- package/dist/native/lib/keyboard.js +24 -0
- package/dist/native/lib/labels.d.ts +15 -0
- package/dist/native/lib/labels.js +17 -0
- package/dist/native/lib/loading.d.ts +10 -0
- package/dist/native/lib/loading.js +15 -0
- package/dist/native/lib/network.d.ts +12 -0
- package/dist/native/lib/network.js +21 -0
- package/dist/native/lib/scheme.d.ts +18 -0
- package/dist/native/lib/scheme.js +22 -0
- package/dist/native/lib/snackbar.d.ts +46 -0
- package/dist/native/lib/snackbar.js +60 -0
- package/dist/native/lib/theme.d.ts +34 -0
- package/dist/native/lib/theme.js +53 -0
- package/dist/native/lib/timezone.d.ts +26 -0
- package/dist/native/lib/timezone.js +95 -0
- package/dist/native/lib/token-color.d.ts +5 -0
- package/dist/native/lib/token-color.js +13 -0
- package/dist/native/lib/token-color.web.d.ts +4 -0
- package/dist/native/lib/token-color.web.js +7 -0
- package/dist/native/lib/tuning-context.d.ts +9 -0
- package/dist/native/lib/tuning-context.js +7 -0
- package/dist/native/lib/tuning.d.ts +24 -0
- package/dist/native/lib/tuning.js +42 -0
- package/dist/native/lib/typography.d.ts +10 -0
- package/dist/native/lib/typography.js +11 -0
- package/dist/native/lib/utils.d.ts +11 -0
- package/dist/native/lib/utils.js +21 -0
- package/dist/native/once/confirm.d.ts +7 -0
- package/dist/native/once/confirm.js +60 -0
- package/dist/native/once/error-boundary.d.ts +28 -0
- package/dist/native/once/error-boundary.js +55 -0
- package/dist/native/once/loading-lock.d.ts +8 -0
- package/dist/native/once/loading-lock.js +28 -0
- package/dist/native/once/offline-banner.d.ts +15 -0
- package/dist/native/once/offline-banner.js +35 -0
- package/dist/native/once/snackbar.d.ts +17 -0
- package/dist/native/once/snackbar.js +106 -0
- package/dist/native/styles.css +46 -0
- package/dist/shared/analytics.d.ts +71 -0
- package/dist/shared/analytics.js +0 -0
- package/dist/shared/button.d.ts +7 -0
- package/dist/shared/button.js +23 -0
- package/dist/shared/form.d.ts +45 -0
- package/dist/shared/form.js +46 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/tokens/contrast-pairs.d.ts +30 -0
- package/dist/tokens/contrast-pairs.js +404 -0
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/index.js +10 -0
- package/dist/tokens/styles.gen.css +250 -0
- package/dist/tokens/tokens.gen.d.ts +141 -0
- package/dist/tokens/tokens.gen.js +206 -0
- package/dist/tuning/catalog.d.ts +27 -0
- package/dist/tuning/catalog.gen.d.ts +4 -0
- package/dist/tuning/catalog.gen.js +397 -0
- package/dist/tuning/catalog.js +128 -0
- package/dist/tuning/color.d.ts +20 -0
- package/dist/tuning/color.js +80 -0
- package/dist/tuning/css.d.ts +35 -0
- package/dist/tuning/css.js +147 -0
- package/dist/tuning/index.d.ts +8 -0
- package/dist/tuning/index.js +9 -0
- package/dist/tuning/model.d.ts +33 -0
- package/dist/tuning/model.js +154 -0
- package/dist/tuning/native.d.ts +35 -0
- package/dist/tuning/native.js +80 -0
- package/dist/tuning/schema.d.ts +69 -0
- package/dist/tuning/schema.js +247 -0
- package/dist/tuning/types.d.ts +75 -0
- package/dist/tuning/types.js +39 -0
- package/dist/web/analytics/line-chart.d.ts +20 -0
- package/dist/web/analytics/line-chart.js +28 -0
- package/dist/web/analytics/metric-card.d.ts +18 -0
- package/dist/web/analytics/metric-card.js +40 -0
- package/dist/web/analytics/multi-line-chart.d.ts +39 -0
- package/dist/web/analytics/multi-line-chart.js +345 -0
- package/dist/web/atom/avatar.d.ts +11 -0
- package/dist/web/atom/avatar.js +24 -0
- package/dist/web/atom/badge.d.ts +2 -0
- package/dist/web/atom/badge.js +3 -0
- package/dist/web/atom/button.d.ts +23 -0
- package/dist/web/atom/button.js +35 -0
- package/dist/web/atom/checkbox.d.ts +19 -0
- package/dist/web/atom/checkbox.js +33 -0
- package/dist/web/atom/colored-value.d.ts +13 -0
- package/dist/web/atom/colored-value.js +24 -0
- package/dist/web/atom/help.d.ts +10 -0
- package/dist/web/atom/help.js +18 -0
- package/dist/web/atom/label.d.ts +2 -0
- package/dist/web/atom/label.js +3 -0
- package/dist/web/atom/segmented-control.d.ts +40 -0
- package/dist/web/atom/segmented-control.js +43 -0
- package/dist/web/atom/select.d.ts +43 -0
- package/dist/web/atom/select.js +93 -0
- package/dist/web/atom/separator.d.ts +2 -0
- package/dist/web/atom/separator.js +3 -0
- package/dist/web/atom/skeleton.d.ts +2 -0
- package/dist/web/atom/skeleton.js +3 -0
- package/dist/web/atom/slider.d.ts +33 -0
- package/dist/web/atom/slider.js +70 -0
- package/dist/web/atom/spinner.d.ts +8 -0
- package/dist/web/atom/spinner.js +14 -0
- package/dist/web/atom/switch.d.ts +11 -0
- package/dist/web/atom/switch.js +10 -0
- package/dist/web/atom/text-area.d.ts +22 -0
- package/dist/web/atom/text-area.js +26 -0
- package/dist/web/atom/text-field.d.ts +17 -0
- package/dist/web/atom/text-field.js +21 -0
- package/dist/web/atom/toggle-chip.d.ts +22 -0
- package/dist/web/atom/toggle-chip.js +28 -0
- package/dist/web/atom/tooltip.d.ts +23 -0
- package/dist/web/atom/tooltip.js +26 -0
- package/dist/web/atom/typography.d.ts +6 -0
- package/dist/web/atom/typography.js +23 -0
- package/dist/web/base/accordion.d.ts +9 -0
- package/dist/web/base/accordion.js +44 -0
- package/dist/web/base/alert.d.ts +11 -0
- package/dist/web/base/alert.js +37 -0
- package/dist/web/base/avatar.d.ts +8 -0
- package/dist/web/base/avatar.js +29 -0
- package/dist/web/base/badge.d.ts +12 -0
- package/dist/web/base/badge.js +26 -0
- package/dist/web/base/breadcrumb.d.ts +16 -0
- package/dist/web/base/breadcrumb.js +72 -0
- package/dist/web/base/button.d.ts +12 -0
- package/dist/web/base/button.js +47 -0
- package/dist/web/base/card.d.ts +19 -0
- package/dist/web/base/card.js +74 -0
- package/dist/web/base/checkbox.d.ts +6 -0
- package/dist/web/base/checkbox.js +21 -0
- package/dist/web/base/dialog.d.ts +20 -0
- package/dist/web/base/dialog.js +92 -0
- package/dist/web/base/dropdown-menu.d.ts +29 -0
- package/dist/web/base/dropdown-menu.js +125 -0
- package/dist/web/base/field.d.ts +27 -0
- package/dist/web/base/field.js +118 -0
- package/dist/web/base/form.d.ts +38 -0
- package/dist/web/base/form.js +110 -0
- package/dist/web/base/input.d.ts +9 -0
- package/dist/web/base/input.js +23 -0
- package/dist/web/base/label.d.ts +6 -0
- package/dist/web/base/label.js +15 -0
- package/dist/web/base/pagination.d.ts +34 -0
- package/dist/web/base/pagination.js +90 -0
- package/dist/web/base/popover.d.ts +11 -0
- package/dist/web/base/popover.js +37 -0
- package/dist/web/base/radio-group.d.ts +7 -0
- package/dist/web/base/radio-group.js +27 -0
- package/dist/web/base/scroll-area.d.ts +10 -0
- package/dist/web/base/scroll-area.js +41 -0
- package/dist/web/base/select.d.ts +17 -0
- package/dist/web/base/select.js +96 -0
- package/dist/web/base/separator.d.ts +6 -0
- package/dist/web/base/separator.js +17 -0
- package/dist/web/base/sheet.d.ts +19 -0
- package/dist/web/base/sheet.js +88 -0
- package/dist/web/base/skeleton.d.ts +5 -0
- package/dist/web/base/skeleton.js +14 -0
- package/dist/web/base/slider.d.ts +9 -0
- package/dist/web/base/slider.js +39 -0
- package/dist/web/base/sonner.d.ts +9 -0
- package/dist/web/base/sonner.js +25 -0
- package/dist/web/base/spinner.d.ts +5 -0
- package/dist/web/base/spinner.js +17 -0
- package/dist/web/base/switch.d.ts +6 -0
- package/dist/web/base/switch.js +19 -0
- package/dist/web/base/table.d.ts +14 -0
- package/dist/web/base/table.js +68 -0
- package/dist/web/base/tabs.d.ts +9 -0
- package/dist/web/base/tabs.js +36 -0
- package/dist/web/base/textarea.d.ts +9 -0
- package/dist/web/base/textarea.js +23 -0
- package/dist/web/base/tooltip.d.ts +9 -0
- package/dist/web/base/tooltip.js +36 -0
- package/dist/web/form/checkbox.d.ts +35 -0
- package/dist/web/form/checkbox.js +91 -0
- package/dist/web/form/radio-group.d.ts +24 -0
- package/dist/web/form/radio-group.js +75 -0
- package/dist/web/form/select.d.ts +16 -0
- package/dist/web/form/select.js +44 -0
- package/dist/web/form/slider.d.ts +19 -0
- package/dist/web/form/slider.js +51 -0
- package/dist/web/form/switch.d.ts +11 -0
- package/dist/web/form/switch.js +50 -0
- package/dist/web/form/text-area.d.ts +10 -0
- package/dist/web/form/text-area.js +31 -0
- package/dist/web/form/text-input.d.ts +10 -0
- package/dist/web/form/text-input.js +42 -0
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js +0 -0
- package/dist/web/layout/accordion.d.ts +26 -0
- package/dist/web/layout/accordion.js +29 -0
- package/dist/web/layout/alert-modal.d.ts +41 -0
- package/dist/web/layout/alert-modal.js +71 -0
- package/dist/web/layout/card.d.ts +17 -0
- package/dist/web/layout/card.js +35 -0
- package/dist/web/layout/description.d.ts +12 -0
- package/dist/web/layout/description.js +20 -0
- package/dist/web/layout/information.d.ts +36 -0
- package/dist/web/layout/information.js +53 -0
- package/dist/web/layout/modal.d.ts +16 -0
- package/dist/web/layout/modal.js +37 -0
- package/dist/web/layout/page-frame.d.ts +37 -0
- package/dist/web/layout/page-frame.js +79 -0
- package/dist/web/layout/scroll-area.d.ts +10 -0
- package/dist/web/layout/scroll-area.js +13 -0
- package/dist/web/layout/sheet.d.ts +32 -0
- package/dist/web/layout/sheet.js +68 -0
- package/dist/web/layout/simple-dialog.d.ts +11 -0
- package/dist/web/layout/simple-dialog.js +24 -0
- package/dist/web/layout/simple-table.d.ts +49 -0
- package/dist/web/layout/simple-table.js +58 -0
- package/dist/web/layout/tabs.d.ts +26 -0
- package/dist/web/layout/tabs.js +42 -0
- package/dist/web/layout/titled-modal.d.ts +33 -0
- package/dist/web/layout/titled-modal.js +59 -0
- package/dist/web/lib/css-vars.d.ts +14 -0
- package/dist/web/lib/css-vars.js +18 -0
- package/dist/web/lib/dialog.d.ts +13 -0
- package/dist/web/lib/dialog.js +0 -0
- package/dist/web/lib/form.d.ts +2 -0
- package/dist/web/lib/form.js +3 -0
- package/dist/web/lib/labels.d.ts +27 -0
- package/dist/web/lib/labels.js +29 -0
- package/dist/web/lib/modal-open-focus.d.ts +17 -0
- package/dist/web/lib/modal-open-focus.js +44 -0
- package/dist/web/lib/restore-focus.d.ts +12 -0
- package/dist/web/lib/restore-focus.js +32 -0
- package/dist/web/lib/utils.d.ts +4 -0
- package/dist/web/lib/utils.js +10 -0
- package/dist/web/styles.css +162 -0
- package/package.json +205 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 <3 (Less Than Three)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,87 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @lt-three/love3
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<3(Less Than Three)共通のデザインシステム。Linear(linear.app)に寄せた、背景の階層・極薄の枠・淡い影・インディゴの主操作。
|
|
4
|
+
web(React + Tailwind CSS v4)と React Native(NativeWind v5)で同じ見た目になる。トークン(色・角丸・影・書体)の実値は TS オブジェクトとしても読める。
|
|
5
|
+
|
|
6
|
+
ライセンスは MIT。
|
|
7
|
+
|
|
8
|
+
## インストール
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @lt-three/love3
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- **web**: `react` `react-dom`(`>=19.3.0 <20`)と `tailwindcss`(v4)を入れる。web の部品が使う依存(Radix・`@tanstack/charts` など)はこのパッケージの `dependencies` に入っているので、別に入れなくてよい。
|
|
15
|
+
- **React Native**: `react` `react-native` `nativewind`(v5)`react-native-css` `tailwindcss` に加えて、使う部品が引く native 側の依存を入れる(`expo`・`expo-router`・`react-native-reanimated`・`react-native-svg` など)。
|
|
16
|
+
native 専用の依存は **optional な `peerDependencies`**。使わない部品の依存は入れなくてよい(どの部品がどれを引くかは `package.json` の `peerDependencies` と部品の import を見る)。
|
|
17
|
+
|
|
18
|
+
公開物は `dist/`(ESM の `.js` と `.d.ts`)。ソースと同じ構造で、部品ごとに 1 ファイルずつ出る。使わない部品の依存は引かれない。
|
|
19
|
+
|
|
20
|
+
## 使い方
|
|
21
|
+
|
|
22
|
+
| import | 中身 |
|
|
23
|
+
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| `@lt-three/love3/styles.css` | Tailwind v4 の `@theme` とライト・ダーク。web と NativeWind で共通 |
|
|
25
|
+
| `@lt-three/love3/tokens` | トークンの実値の TS オブジェクト(`tokens.light` / `tokens.dark`)・`cssVar`・型。CSS が使えない RN のチャート・Reanimated 向け。`node:` の組み込みも引かない |
|
|
26
|
+
| `@lt-three/love3/tokens/contrast` | コントラストを検査する前景 / 背景の組(`CONTRAST_PAIRS`)と、理由つきの既知の例外(`KNOWN_CONTRAST_EXCEPTIONS`)。データだけ |
|
|
27
|
+
| `@lt-three/love3/tuning` | トークンを実行時に上書きする「調整」の形式・検証・適用(`zod` だけを引く) |
|
|
28
|
+
| `@lt-three/love3/web` / `@lt-three/love3/native` / `@lt-three/love3/shared` | 各レイヤーの入口(`index.ts`) |
|
|
29
|
+
| `@lt-three/love3/web/atom/button.tsx` のように **拡張子つき** | web コンポーネント。`web/*.ts`(hook・util)と `web/*.tsx` |
|
|
30
|
+
| `@lt-three/love3/web/styles.css` | web のアプリが CSS の入口で import する。Tailwind・フォント・トークン・ベーススタイル |
|
|
31
|
+
| `@lt-three/love3/native/atom/button.tsx` のように **拡張子つき** | native コンポーネント |
|
|
32
|
+
| `@lt-three/love3/native/styles.css` | **実機(Metro / NativeWind v5)の CSS の入口**。Tailwind・`nativewind/theme`・トークン・部品のクラスの検出と、`dark:` を `prefers-color-scheme` にする上書き |
|
|
33
|
+
| `@lt-three/love3/shared/…`(`.ts` / `.tsx`) | web / native 共通の props 型・variant 定義 |
|
|
34
|
+
|
|
35
|
+
**ワイルドカードの export は拡張子つきのキー**(`./web/*.tsx` / `./web/*.ts`)。exports は拡張子を探してくれないので、利用側も拡張子つきで import する
|
|
36
|
+
(TypeScript では `allowImportingTsExtensions` を有効にする)。拡張子なし(`.../atom/button`)は解決できない。指定子が指す先は `dist/` の `.js` と型宣言の `.d.ts`。
|
|
37
|
+
|
|
38
|
+
### web
|
|
39
|
+
|
|
40
|
+
CSS の入口で 1 度だけ import する。
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@import "@lt-three/love3/web/styles.css";
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { Button } from "@lt-three/love3/web/atom/button.tsx";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
部品が使う Tailwind のクラスは、この CSS の `@source` が `dist/` から拾う。アプリ自身のソースは、バンドラのプロジェクトルートを基準にした Tailwind の自動検出に任せる。
|
|
51
|
+
ダークは `<html class="dark">` で切り替える。
|
|
52
|
+
|
|
53
|
+
### React Native
|
|
54
|
+
|
|
55
|
+
アプリの `global.css` で 1 度だけ import する(NativeWind v5 / react-native-css が Tailwind v4 としてコンパイルする)。
|
|
56
|
+
|
|
57
|
+
```css
|
|
58
|
+
@import "@lt-three/love3/native/styles.css";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
native の `dark:` は**クラスではなく OS の配色設定**(`prefers-color-scheme`)で解決する。`.dark` を祖先セレクタに持つと、react-native-css がそのビューを container として扱い、
|
|
62
|
+
子孫の ScrollView が pan を受け取れなくなるため。アプリ内のテーマ設定は `Appearance.setColorScheme()` で切り替える。
|
|
63
|
+
|
|
64
|
+
iOS の SwiftUI Charts を使う部品(`line-chart.ios.tsx` / `pie-chart.ios.tsx`)は、iOS のアプリが拡張子つきで明示して import する。
|
|
65
|
+
|
|
66
|
+
### トークン
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { cssVar, tokens } from "@lt-three/love3/tokens";
|
|
70
|
+
|
|
71
|
+
tokens.light["ink-900"]; // 実値("#1b1c20")
|
|
72
|
+
cssVar("ink-900"); // "var(--ink-900)"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
変数名は shadcn 互換の名前(`--background` / `--primary` など)に、`--ink-*` / `--line*` / `--lt-three` などの生トークンを足したもの。
|
|
76
|
+
|
|
77
|
+
## 注意: `.theme-light` はセマンティックなクラスを明るくしない
|
|
78
|
+
|
|
79
|
+
`.theme-light`(ライト固定のスコープ)が再定義するのは**生トークンだけ**(`--ink-*` / `--line*` / `--frame` / `--paper` / `--raised` / `--overlay` / `--wash` / `--scrim` / `--shadow-color` / `--action-ink` / `--state-*` / `--chart-*`)。
|
|
80
|
+
`--background` / `--foreground` / `--primary` などのセマンティックな変数は `:root` で `var(--paper)` のように宣言されていて、**宣言した要素で解決されてから子孫へ継承される**。
|
|
81
|
+
そのため `<html class="dark">` の下に `.theme-light` を置いても、その子孫で `bg-background` / `text-foreground` / `bg-primary` などは**暗いまま**になる
|
|
82
|
+
(`bg-paper` / `text-ink-900` のような生トークンのクラスなら明るくなる)。
|
|
83
|
+
love3 の部品は `.theme-light` を使わない。常にライトにしたいページでは、`.theme-light` の中で生トークンのクラスを使うか、`.theme-light` にもセマンティックな変数の再宣言を足す。
|
|
84
|
+
|
|
85
|
+
## ライセンス
|
|
86
|
+
|
|
87
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ChartCommonProps as ChartCommonProps$1, LineChartSharedProps, LinePoint, LineSeries, MultiLineChartSharedProps } from "../../shared/analytics.js";
|
|
2
|
+
import { ViewStyle } from "react-native";
|
|
3
|
+
//#region src/native/analytics/chart.types.d.ts
|
|
4
|
+
export type PieSlice = {
|
|
5
|
+
label: string;
|
|
6
|
+
value: number;
|
|
7
|
+
color?: string;
|
|
8
|
+
};
|
|
9
|
+
type ChartCommonProps = ChartCommonProps$1 & {
|
|
10
|
+
style?: ViewStyle;
|
|
11
|
+
/**
|
|
12
|
+
* ネイティブチャート非対応プラットフォームで出す文言。
|
|
13
|
+
* 共有パッケージなので既定値のみ持ち、翻訳は使用側が渡す。
|
|
14
|
+
*/
|
|
15
|
+
fallbackText?: string;
|
|
16
|
+
};
|
|
17
|
+
export type LineChartProps = ChartCommonProps & LineChartSharedProps;
|
|
18
|
+
export type PieChartProps = ChartCommonProps & {
|
|
19
|
+
data: PieSlice[];
|
|
20
|
+
/** 中心を空けたドーナツ表示にする。 */
|
|
21
|
+
donut?: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type MultiLineChartProps = ChartCommonProps & MultiLineChartSharedProps;
|
|
24
|
+
//#endregion
|
|
25
|
+
export type { LinePoint, LineSeries };
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useChartPalette } from "../lib/chart-palette.js";
|
|
2
|
+
import { Chart, Host } from "@expo/ui/swift-ui";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/native/analytics/line-chart.ios.tsx
|
|
6
|
+
function LineChart({ data, color, height = 220, style }) {
|
|
7
|
+
const palette = useChartPalette();
|
|
8
|
+
return /* @__PURE__ */ jsx(Host, {
|
|
9
|
+
style: [{ height }, style],
|
|
10
|
+
children: /* @__PURE__ */ jsx(Chart, {
|
|
11
|
+
data: data.map((point) => ({
|
|
12
|
+
x: point.x,
|
|
13
|
+
y: point.y
|
|
14
|
+
})),
|
|
15
|
+
type: "line",
|
|
16
|
+
showGrid: true,
|
|
17
|
+
animate: true,
|
|
18
|
+
lineStyle: { color: color ?? palette[0] }
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { LineChart };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
2
|
+
import { Suspense, lazy } from "react";
|
|
3
|
+
import { Platform, View } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/native/analytics/line-chart.tsx
|
|
7
|
+
const SwiftUILineChart = lazy(() => import("./line-chart.ios.js").then((module) => ({ default: module.LineChart })));
|
|
8
|
+
const DEFAULT_FALLBACK_TEXT = "チャートは現在 iOS でのみ表示できます";
|
|
9
|
+
const DEFAULT_HEIGHT = 220;
|
|
10
|
+
function LineChart(props) {
|
|
11
|
+
const height = props.height ?? DEFAULT_HEIGHT;
|
|
12
|
+
if (Platform.OS !== "ios") return /* @__PURE__ */ jsx(LineChartFallback, {
|
|
13
|
+
height,
|
|
14
|
+
text: props.fallbackText
|
|
15
|
+
});
|
|
16
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
17
|
+
fallback: /* @__PURE__ */ jsx(View, { style: { height } }),
|
|
18
|
+
children: /* @__PURE__ */ jsx(SwiftUILineChart, { ...props })
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function LineChartFallback({ height, text }) {
|
|
22
|
+
return /* @__PURE__ */ jsx(View, {
|
|
23
|
+
style: { height },
|
|
24
|
+
className: "items-center justify-center",
|
|
25
|
+
children: /* @__PURE__ */ jsx(Text$1, {
|
|
26
|
+
className: "text-muted-foreground text-sm",
|
|
27
|
+
children: text ?? DEFAULT_FALLBACK_TEXT
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { LineChart };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MetricCardSharedProps } from "../../shared/analytics.js";
|
|
2
|
+
//#region src/native/analytics/metric-card.d.ts
|
|
3
|
+
export type MetricCardProps = MetricCardSharedProps;
|
|
4
|
+
/**
|
|
5
|
+
* 面付きの単一指標。`@lt-three/web` の analytics/metric-card に対応する。
|
|
6
|
+
* 中身(ラベル + 大型の等幅数値 + 補助)は `atom/readout` が持ち、
|
|
7
|
+
* ここは web と同じく Card 外装を着せる役だけを担う。
|
|
8
|
+
*/
|
|
9
|
+
export declare function MetricCard({ label, value, subValue, trend, className }: MetricCardProps): import("react").JSX.Element;
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Readout } from "../atom/readout.js";
|
|
4
|
+
import { Panel } from "../layout/panel.js";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/native/analytics/metric-card.tsx
|
|
8
|
+
/**
|
|
9
|
+
* 面付きの単一指標。`@lt-three/web` の analytics/metric-card に対応する。
|
|
10
|
+
* 中身(ラベル + 大型の等幅数値 + 補助)は `atom/readout` が持ち、
|
|
11
|
+
* ここは web と同じく Card 外装を着せる役だけを担う。
|
|
12
|
+
*/
|
|
13
|
+
function MetricCard({ label, value, subValue, trend, className }) {
|
|
14
|
+
const up = useTokenColor("--state-success");
|
|
15
|
+
const down = useTokenColor("--state-error");
|
|
16
|
+
const valueColor = trend === void 0 || trend === 0 ? void 0 : trend > 0 ? up : down;
|
|
17
|
+
return /* @__PURE__ */ jsx(Panel, {
|
|
18
|
+
className: cn("p-4", className),
|
|
19
|
+
children: /* @__PURE__ */ jsx(Readout, {
|
|
20
|
+
label,
|
|
21
|
+
value,
|
|
22
|
+
sub: subValue,
|
|
23
|
+
valueColor
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { MetricCard };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MultiLineChartProps } from "./chart.types.js";
|
|
2
|
+
//#region src/native/analytics/multi-line-chart.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* 複数系列の折れ線。移植元は `@lt-three/web` の analytics/line-chart(Recharts・複数キー)で、web の love3 では
|
|
5
|
+
* `analytics/multi-line-chart`(`@tanstack/charts`)が対応する(props は `shared/analytics.ts` で同じ)。
|
|
6
|
+
*
|
|
7
|
+
* **`@expo/ui` の Chart は 1 系列しか描けない**(型定義にも line/area は single-series と
|
|
8
|
+
* 明記されている)ので、同じ軸に 2 本以上載せたいものはこちらを使う。残高とエクイティの
|
|
9
|
+
* ように単位も軸も同じ系列を 2 枚のカードに分けると、上下を見比べないと関係が読めない。
|
|
10
|
+
*
|
|
11
|
+
* 描画は react-native-svg。SwiftUI Charts と違って外枠は描かず、目盛りの罫線だけを敷く
|
|
12
|
+
* (使用側が `Panel` で囲うと枠が二重になるため)。
|
|
13
|
+
*
|
|
14
|
+
* タップすると、その位置の各系列の値を読み出す。折れ線は目盛りだけだと概形しか読めない。
|
|
15
|
+
*/
|
|
16
|
+
export declare function MultiLineChart({ series, height, formatValue, emptyText, style, accessibilityLabel }: MultiLineChartProps): import("react").JSX.Element;
|
|
17
|
+
//#endregion
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { Text as Text$2 } from "../base/text.js";
|
|
3
|
+
import { tabularNums } from "../lib/typography.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Pressable, View } from "react-native";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import Svg, { Circle, Line, Path, Text as Text$1 } from "react-native-svg";
|
|
8
|
+
|
|
9
|
+
//#region src/native/analytics/multi-line-chart.tsx
|
|
10
|
+
/**
|
|
11
|
+
* 複数系列の折れ線。移植元は `@lt-three/web` の analytics/line-chart(Recharts・複数キー)で、web の love3 では
|
|
12
|
+
* `analytics/multi-line-chart`(`@tanstack/charts`)が対応する(props は `shared/analytics.ts` で同じ)。
|
|
13
|
+
*
|
|
14
|
+
* **`@expo/ui` の Chart は 1 系列しか描けない**(型定義にも line/area は single-series と
|
|
15
|
+
* 明記されている)ので、同じ軸に 2 本以上載せたいものはこちらを使う。残高とエクイティの
|
|
16
|
+
* ように単位も軸も同じ系列を 2 枚のカードに分けると、上下を見比べないと関係が読めない。
|
|
17
|
+
*
|
|
18
|
+
* 描画は react-native-svg。SwiftUI Charts と違って外枠は描かず、目盛りの罫線だけを敷く
|
|
19
|
+
* (使用側が `Panel` で囲うと枠が二重になるため)。
|
|
20
|
+
*
|
|
21
|
+
* タップすると、その位置の各系列の値を読み出す。折れ線は目盛りだけだと概形しか読めない。
|
|
22
|
+
*/
|
|
23
|
+
function MultiLineChart({ series, height = 220, formatValue = (value) => String(Math.round(value)), emptyText = "データがありません", style, accessibilityLabel }) {
|
|
24
|
+
const line = useTokenColor("--line");
|
|
25
|
+
const mutedInk = useTokenColor("--ink-500");
|
|
26
|
+
const [width, setWidth] = useState(0);
|
|
27
|
+
const [pickedX, setPickedX] = useState(null);
|
|
28
|
+
const withData = series.filter((entry) => entry.points.length > 0);
|
|
29
|
+
const values = withData.flatMap((entry) => entry.points.map((point) => point.y));
|
|
30
|
+
if (withData.length === 0) return /* @__PURE__ */ jsx(View, {
|
|
31
|
+
style: [{ height }, style],
|
|
32
|
+
className: "items-center justify-center",
|
|
33
|
+
children: /* @__PURE__ */ jsx(Text$2, {
|
|
34
|
+
className: "text-muted-foreground text-sm",
|
|
35
|
+
children: emptyText
|
|
36
|
+
})
|
|
37
|
+
});
|
|
38
|
+
const padding = {
|
|
39
|
+
top: 8,
|
|
40
|
+
right: 8,
|
|
41
|
+
bottom: 8,
|
|
42
|
+
left: 72
|
|
43
|
+
};
|
|
44
|
+
const plotWidth = Math.max(width - padding.left - padding.right, 0);
|
|
45
|
+
const plotHeight = height - padding.top - padding.bottom;
|
|
46
|
+
const min = Math.min(...values);
|
|
47
|
+
const max = Math.max(...values);
|
|
48
|
+
const span = max - min || Math.max(Math.abs(max), 1);
|
|
49
|
+
const low = max === min ? min - span / 2 : min;
|
|
50
|
+
const high = max === min ? max + span / 2 : max;
|
|
51
|
+
const toY = (value) => padding.top + (1 - (value - low) / (high - low)) * plotHeight;
|
|
52
|
+
const times = withData.flatMap((entry) => entry.points.map((point) => point.t));
|
|
53
|
+
const timed = times.every((time) => time !== void 0) && times.length > 0;
|
|
54
|
+
const tMin = timed ? Math.min(...times) : 0;
|
|
55
|
+
const tSpan = (timed ? Math.max(...times) : 0) - tMin;
|
|
56
|
+
const toX = (index, count, time) => {
|
|
57
|
+
if (timed && time !== void 0) return padding.left + (tSpan === 0 ? plotWidth / 2 : (time - tMin) / tSpan * plotWidth);
|
|
58
|
+
return padding.left + (count === 1 ? plotWidth / 2 : index / (count - 1) * plotWidth);
|
|
59
|
+
};
|
|
60
|
+
const ticks = [
|
|
61
|
+
high,
|
|
62
|
+
(high + low) / 2,
|
|
63
|
+
low
|
|
64
|
+
];
|
|
65
|
+
const picked = pickedX === null ? [] : withData.map((entry) => ({
|
|
66
|
+
entry,
|
|
67
|
+
hit: nearestPoint(entry, pickedX, toX)
|
|
68
|
+
})).filter((row) => row.hit !== null);
|
|
69
|
+
const marker = picked[0];
|
|
70
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
71
|
+
style,
|
|
72
|
+
...accessibilityLabel === void 0 ? {} : {
|
|
73
|
+
accessible: true,
|
|
74
|
+
accessibilityRole: "image",
|
|
75
|
+
accessibilityLabel
|
|
76
|
+
},
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsx(Pressable, {
|
|
79
|
+
focusable: false,
|
|
80
|
+
tabIndex: -1,
|
|
81
|
+
onLayout: (event) => setWidth(event.nativeEvent.layout.width),
|
|
82
|
+
onPress: (event) => {
|
|
83
|
+
const x = pressX(event);
|
|
84
|
+
if (x === null) return;
|
|
85
|
+
setPickedX(x < padding.left || x > padding.left + plotWidth ? null : x);
|
|
86
|
+
},
|
|
87
|
+
children: /* @__PURE__ */ jsxs(Svg, {
|
|
88
|
+
width,
|
|
89
|
+
height,
|
|
90
|
+
children: [
|
|
91
|
+
ticks.map((tick) => /* @__PURE__ */ jsx(Line, {
|
|
92
|
+
x1: padding.left,
|
|
93
|
+
x2: padding.left + plotWidth,
|
|
94
|
+
y1: toY(tick),
|
|
95
|
+
y2: toY(tick),
|
|
96
|
+
stroke: line,
|
|
97
|
+
strokeWidth: 1
|
|
98
|
+
}, `grid-${tick}`)),
|
|
99
|
+
ticks.map((tick) => /* @__PURE__ */ jsx(Text$1, {
|
|
100
|
+
x: padding.left - 8,
|
|
101
|
+
y: toY(tick) + 4,
|
|
102
|
+
fontSize: 10,
|
|
103
|
+
fill: mutedInk,
|
|
104
|
+
textAnchor: "end",
|
|
105
|
+
children: formatValue(tick)
|
|
106
|
+
}, `label-${tick}`)),
|
|
107
|
+
withData.map((entry) => /* @__PURE__ */ jsx(Path, {
|
|
108
|
+
d: pathOf(entry, toX, toY),
|
|
109
|
+
stroke: entry.color,
|
|
110
|
+
strokeWidth: entry.dashed === true ? 1 : 1.5,
|
|
111
|
+
strokeDasharray: entry.dashed === true ? "4 3" : void 0,
|
|
112
|
+
fill: "none"
|
|
113
|
+
}, entry.key)),
|
|
114
|
+
marker !== void 0 && /* @__PURE__ */ jsx(Line, {
|
|
115
|
+
x1: marker.hit.x,
|
|
116
|
+
x2: marker.hit.x,
|
|
117
|
+
y1: padding.top,
|
|
118
|
+
y2: padding.top + plotHeight,
|
|
119
|
+
stroke: mutedInk,
|
|
120
|
+
strokeWidth: 1,
|
|
121
|
+
strokeDasharray: "2 2"
|
|
122
|
+
}),
|
|
123
|
+
picked.map((row) => /* @__PURE__ */ jsx(Circle, {
|
|
124
|
+
cx: row.hit.x,
|
|
125
|
+
cy: toY(row.hit.value.y),
|
|
126
|
+
r: 3,
|
|
127
|
+
fill: row.entry.color
|
|
128
|
+
}, `dot-${row.entry.key}`))
|
|
129
|
+
]
|
|
130
|
+
})
|
|
131
|
+
}),
|
|
132
|
+
marker !== void 0 && /* @__PURE__ */ jsxs(View, {
|
|
133
|
+
className: "border-line bg-popover rounded-control mt-2 gap-1 border p-2.5 shadow-md",
|
|
134
|
+
children: [/* @__PURE__ */ jsx(Text$2, {
|
|
135
|
+
style: tabularNums,
|
|
136
|
+
className: "text-muted-foreground font-mono text-[11px]",
|
|
137
|
+
children: String(marker.hit.value.x)
|
|
138
|
+
}), picked.map((row) => /* @__PURE__ */ jsxs(View, {
|
|
139
|
+
className: "flex-row items-center justify-between gap-3",
|
|
140
|
+
children: [/* @__PURE__ */ jsxs(View, {
|
|
141
|
+
className: "flex-row items-center gap-1.5",
|
|
142
|
+
children: [/* @__PURE__ */ jsx(View, { style: {
|
|
143
|
+
width: 10,
|
|
144
|
+
height: 2,
|
|
145
|
+
backgroundColor: row.entry.color
|
|
146
|
+
} }), /* @__PURE__ */ jsx(Text$2, {
|
|
147
|
+
className: "text-muted-foreground text-[11px]",
|
|
148
|
+
children: row.entry.label
|
|
149
|
+
})]
|
|
150
|
+
}), /* @__PURE__ */ jsx(Text$2, {
|
|
151
|
+
style: tabularNums,
|
|
152
|
+
className: "text-foreground font-mono text-[13px] font-semibold",
|
|
153
|
+
children: formatValue(row.hit.value.y)
|
|
154
|
+
})]
|
|
155
|
+
}, `read-${row.entry.key}`))]
|
|
156
|
+
}),
|
|
157
|
+
/* @__PURE__ */ jsx(View, {
|
|
158
|
+
className: "flex-row flex-wrap gap-x-4 gap-y-1 px-1 pt-2",
|
|
159
|
+
children: series.map((entry) => /* @__PURE__ */ jsxs(View, {
|
|
160
|
+
className: "flex-row items-center gap-1.5",
|
|
161
|
+
children: [/* @__PURE__ */ jsx(View, { style: {
|
|
162
|
+
width: 10,
|
|
163
|
+
height: 2,
|
|
164
|
+
backgroundColor: entry.color,
|
|
165
|
+
opacity: entry.points.length > 0 ? 1 : .4
|
|
166
|
+
} }), /* @__PURE__ */ jsx(Text$2, {
|
|
167
|
+
className: "text-muted-foreground text-[11px]",
|
|
168
|
+
children: entry.label
|
|
169
|
+
})]
|
|
170
|
+
}, `legend-${entry.key}`))
|
|
171
|
+
})
|
|
172
|
+
]
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 押した位置(押した要素の左端からの x)。実機は `locationX`。
|
|
177
|
+
* react-native-web の `onPress` は DOM の click を渡す(`locationX` が無い)ので、そのときは要素の左端との差で求める。
|
|
178
|
+
* 位置の無い click(キーボード等)は null。
|
|
179
|
+
*/
|
|
180
|
+
function pressX(event) {
|
|
181
|
+
const { locationX } = event.nativeEvent;
|
|
182
|
+
if (typeof locationX === "number" && Number.isFinite(locationX)) return locationX;
|
|
183
|
+
const dom = event.nativeEvent;
|
|
184
|
+
if (dom.detail === 0) return null;
|
|
185
|
+
const target = event.currentTarget;
|
|
186
|
+
return dom.clientX - target.getBoundingClientRect().left;
|
|
187
|
+
}
|
|
188
|
+
/** 系列を 1 本の SVG パスにする。 */
|
|
189
|
+
function pathOf(entry, toX, toY) {
|
|
190
|
+
const count = entry.points.length;
|
|
191
|
+
return entry.points.map((point, index) => `${index === 0 ? "M" : "L"}${toX(index, count, point.t)},${toY(point.y)}`).join(" ");
|
|
192
|
+
}
|
|
193
|
+
/** 押した x にいちばん近い点を、その描画位置ごと返す。 */
|
|
194
|
+
function nearestPoint(entry, pickedX, toX) {
|
|
195
|
+
const count = entry.points.length;
|
|
196
|
+
let best;
|
|
197
|
+
let bestX = 0;
|
|
198
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
199
|
+
for (let index = 0; index < count; index++) {
|
|
200
|
+
const x = toX(index, count, entry.points[index]?.t);
|
|
201
|
+
const distance = Math.abs(x - pickedX);
|
|
202
|
+
if (distance < bestDistance) {
|
|
203
|
+
bestDistance = distance;
|
|
204
|
+
bestX = x;
|
|
205
|
+
best = entry.points[index];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return best === void 0 ? null : {
|
|
209
|
+
x: bestX,
|
|
210
|
+
value: best
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
//#endregion
|
|
215
|
+
export { MultiLineChart };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PieChartProps } from "./chart.types.js";
|
|
2
|
+
//#region src/native/analytics/pie-chart.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* 円グラフ(react-native-svg)。移植元の既定(Android / web)実装。iOS の SwiftUI Charts 版(`pie-chart.ios.tsx`)は
|
|
5
|
+
* `@expo/ui` が要るので、placeholder の仕組み(G5)と一緒に足す。足すまでは iOS もこの実装で描く。
|
|
6
|
+
*
|
|
7
|
+
* 描画は `multi-line-chart` と同じ react-native-svg。**「iOS のみ」のプレースホルダに
|
|
8
|
+
* しない**のは、勝敗比率・ロング / ショート・銘柄内訳がこのコンポーネントだけで出ており、
|
|
9
|
+
* Android では画面の主役が丸ごと文言に置き換わってしまうため。
|
|
10
|
+
*
|
|
11
|
+
* **凡例はここで持たない。** 使用側(口座のチャート)が色付きの内訳リストを円の下に
|
|
12
|
+
* 必ず並べるので、ここで凡例を出すと同じものが 2 段になる。円の高さもそのぶん削れる。
|
|
13
|
+
*/
|
|
14
|
+
export declare function PieChart({ data, donut, height, style, accessibilityLabel }: PieChartProps): import("react").JSX.Element;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useChartPalette } from "../lib/chart-palette.js";
|
|
2
|
+
import { Chart, Host } from "@expo/ui/swift-ui";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/native/analytics/pie-chart.ios.tsx
|
|
6
|
+
function PieChart({ data, donut, height = 220, style }) {
|
|
7
|
+
const palette = useChartPalette();
|
|
8
|
+
return /* @__PURE__ */ jsx(Host, {
|
|
9
|
+
style: [{ height }, style],
|
|
10
|
+
children: /* @__PURE__ */ jsx(Chart, {
|
|
11
|
+
data: data.map((slice, index) => ({
|
|
12
|
+
x: slice.label,
|
|
13
|
+
y: slice.value,
|
|
14
|
+
color: slice.color ?? palette[index % palette.length]
|
|
15
|
+
})),
|
|
16
|
+
type: "pie",
|
|
17
|
+
animate: true,
|
|
18
|
+
pieStyle: donut ? { innerRadius: .6 } : void 0
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { PieChart };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { useChartPalette } from "../lib/chart-palette.js";
|
|
3
|
+
import { Text as Text$2 } from "../base/text.js";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import Svg, { Circle, Path } from "react-native-svg";
|
|
7
|
+
|
|
8
|
+
//#region src/native/analytics/pie-chart.tsx
|
|
9
|
+
/**
|
|
10
|
+
* 円グラフ(react-native-svg)。移植元の既定(Android / web)実装。iOS の SwiftUI Charts 版(`pie-chart.ios.tsx`)は
|
|
11
|
+
* `@expo/ui` が要るので、placeholder の仕組み(G5)と一緒に足す。足すまでは iOS もこの実装で描く。
|
|
12
|
+
*
|
|
13
|
+
* 描画は `multi-line-chart` と同じ react-native-svg。**「iOS のみ」のプレースホルダに
|
|
14
|
+
* しない**のは、勝敗比率・ロング / ショート・銘柄内訳がこのコンポーネントだけで出ており、
|
|
15
|
+
* Android では画面の主役が丸ごと文言に置き換わってしまうため。
|
|
16
|
+
*
|
|
17
|
+
* **凡例はここで持たない。** 使用側(口座のチャート)が色付きの内訳リストを円の下に
|
|
18
|
+
* 必ず並べるので、ここで凡例を出すと同じものが 2 段になる。円の高さもそのぶん削れる。
|
|
19
|
+
*/
|
|
20
|
+
function PieChart({ data, donut, height = 220, style, accessibilityLabel }) {
|
|
21
|
+
const palette = useChartPalette();
|
|
22
|
+
const fallbackColor = useTokenColor("--chart-1");
|
|
23
|
+
const total = data.reduce((sum, slice) => sum + Math.max(slice.value, 0), 0);
|
|
24
|
+
const colorOf = (slice, index) => slice.color ?? palette[index % palette.length] ?? fallbackColor;
|
|
25
|
+
const size = height;
|
|
26
|
+
const radius = size / 2;
|
|
27
|
+
const inner = donut ? radius * .6 : 0;
|
|
28
|
+
return /* @__PURE__ */ jsx(View, {
|
|
29
|
+
style,
|
|
30
|
+
...accessibilityLabel === void 0 ? {} : {
|
|
31
|
+
accessible: true,
|
|
32
|
+
accessibilityRole: "image",
|
|
33
|
+
accessibilityLabel
|
|
34
|
+
},
|
|
35
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
36
|
+
style: { height: size },
|
|
37
|
+
className: "items-center justify-center",
|
|
38
|
+
children: total > 0 ? /* @__PURE__ */ jsx(Svg, {
|
|
39
|
+
width: size,
|
|
40
|
+
height: size,
|
|
41
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
42
|
+
children: data.length === 1 && data[0] ? /* @__PURE__ */ jsx(Circle, {
|
|
43
|
+
cx: radius,
|
|
44
|
+
cy: radius,
|
|
45
|
+
r: (radius + inner) / 2,
|
|
46
|
+
stroke: colorOf(data[0], 0),
|
|
47
|
+
strokeWidth: radius - inner,
|
|
48
|
+
fill: "none"
|
|
49
|
+
}) : slicePaths(data, total, radius, inner).map(({ slice, d }, index) => /* @__PURE__ */ jsx(Path, {
|
|
50
|
+
d,
|
|
51
|
+
fill: colorOf(slice, index)
|
|
52
|
+
}, slice.label))
|
|
53
|
+
}) : /* @__PURE__ */ jsx(Text$2, {
|
|
54
|
+
className: "text-muted-foreground text-sm",
|
|
55
|
+
children: "–"
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/** 各スライスを SVG のパスにする。12 時から時計回りに並べる(SwiftUI Charts と同じ向き)。 */
|
|
61
|
+
function slicePaths(data, total, radius, inner) {
|
|
62
|
+
let angle = -Math.PI / 2;
|
|
63
|
+
return data.map((slice) => {
|
|
64
|
+
const sweep = Math.max(slice.value, 0) / total * Math.PI * 2;
|
|
65
|
+
const end = angle + sweep;
|
|
66
|
+
const large = sweep > Math.PI ? 1 : 0;
|
|
67
|
+
const outerStart = point(radius, radius, radius, angle);
|
|
68
|
+
const outerEnd = point(radius, radius, radius, end);
|
|
69
|
+
const innerEnd = point(radius, radius, inner, end);
|
|
70
|
+
const innerStart = point(radius, radius, inner, angle);
|
|
71
|
+
angle = end;
|
|
72
|
+
return {
|
|
73
|
+
slice,
|
|
74
|
+
d: [
|
|
75
|
+
`M ${outerStart.x} ${outerStart.y}`,
|
|
76
|
+
`A ${radius} ${radius} 0 ${large} 1 ${outerEnd.x} ${outerEnd.y}`,
|
|
77
|
+
`L ${innerEnd.x} ${innerEnd.y}`,
|
|
78
|
+
inner > 0 ? `A ${inner} ${inner} 0 ${large} 0 ${innerStart.x} ${innerStart.y}` : "",
|
|
79
|
+
"Z"
|
|
80
|
+
].filter(Boolean).join(" ")
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function point(cx, cy, r, angle) {
|
|
85
|
+
return {
|
|
86
|
+
x: cx + r * Math.cos(angle),
|
|
87
|
+
y: cy + r * Math.sin(angle)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
export { PieChart };
|