@lt-three/love3 0.0.0 → 0.1.1
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 +85 -1
- 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 +18 -0
- package/dist/native/analytics/multi-line-chart.js +216 -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 +12 -0
- package/dist/native/atom/separator.js +16 -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 +22 -0
- package/dist/native/form/form.js +44 -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 +48 -0
- package/dist/native/lib/confirm.js +69 -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 +16 -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 +11 -0
- package/dist/native/lib/network.js +20 -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 +45 -0
- package/dist/native/lib/snackbar.js +59 -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 +39 -0
- package/dist/web/atom/segmented-control.js +42 -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 +23 -0
- package/dist/web/atom/text-area.js +27 -0
- package/dist/web/atom/text-field.d.ts +18 -0
- package/dist/web/atom/text-field.js +22 -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 +32 -0
- package/dist/web/layout/titled-modal.js +58 -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 +203 -4
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { FONT_KEYS, FONT_TOKEN, RADIUS_ROLES } from "./types.js";
|
|
2
|
+
import { bodyLineHeight, colorValue, normalize } from "./model.js";
|
|
3
|
+
|
|
4
|
+
//#region src/tuning/css.ts
|
|
5
|
+
/** The shadow preset (Tailwind's default shadows). The love3 default is a soft shadow using `--shadow-color` (the `theme` in `definition.ts`). */
|
|
6
|
+
const SHADOW_PRESET = {
|
|
7
|
+
"2xs": "0 1px rgb(0 0 0 / 0.05)",
|
|
8
|
+
xs: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
|
|
9
|
+
sm: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
|
|
10
|
+
md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
|
|
11
|
+
lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
12
|
+
xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
|
|
13
|
+
"2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)"
|
|
14
|
+
};
|
|
15
|
+
/** The preset that removes shadows (the same steps as `SHADOW_PRESET`). */
|
|
16
|
+
const SHADOW_NONE = {
|
|
17
|
+
"2xs": "none",
|
|
18
|
+
xs: "none",
|
|
19
|
+
sm: "none",
|
|
20
|
+
md: "none",
|
|
21
|
+
lg: "none",
|
|
22
|
+
xl: "none",
|
|
23
|
+
"2xl": "none"
|
|
24
|
+
};
|
|
25
|
+
/** The shadow values a tuning swaps in. The default (`default`) is not swapped. */
|
|
26
|
+
function shadowValues(n) {
|
|
27
|
+
if (n.shadow === "default") return [];
|
|
28
|
+
return Object.entries(n.shadow === "none" ? SHADOW_NONE : SHADOW_PRESET);
|
|
29
|
+
}
|
|
30
|
+
/** The names of the color tokens that were changed (in either light or dark), in definition order. */
|
|
31
|
+
function touchedColors(n, catalog) {
|
|
32
|
+
return catalog.colors.map((color) => color.name).filter((name) => n.tokens.light[name] !== void 0 || n.tokens.dark[name] !== void 0);
|
|
33
|
+
}
|
|
34
|
+
function decl(name, value) {
|
|
35
|
+
return ` --${name}: ${value};`;
|
|
36
|
+
}
|
|
37
|
+
function block(selector, lines) {
|
|
38
|
+
return lines.length === 0 ? "" : `${selector} {\n${lines.join("\n")}\n}`;
|
|
39
|
+
}
|
|
40
|
+
/** The roles that differ from the defaults (already `normalize`d, so what remains in `radius` is the difference). */
|
|
41
|
+
function radiusRoles(n) {
|
|
42
|
+
return RADIUS_ROLES.flatMap((role) => {
|
|
43
|
+
const px = n.radius[role];
|
|
44
|
+
return px === void 0 ? [] : [[`radius-${role}`, `${px}px`]];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* **The CSS injected into `<style id="love3-tuning">` at runtime.** An empty string when everything is at the defaults (nothing is injected).
|
|
49
|
+
*
|
|
50
|
+
* It has the same shape as the generated CSS of love3 (`:root` for light, `.dark` for dark), and is loaded later to override it.
|
|
51
|
+
* - For a changed color, **write both light and dark**. In the generated CSS `.dark` comes after `:root`, so if only light were overridden,
|
|
52
|
+
* the `:root` placed later would beat the generated `.dark` and flatten dark mode too. The effective value is also written to `.dark` to protect dark separately
|
|
53
|
+
* - Semantic references, radius, typeface, and body size go only in `:root` (the generated `.dark` redefines only color tokens)
|
|
54
|
+
* - The radius (`--radius-control` / `--radius-surface`) is a variable of Tailwind's `@theme`, but at runtime it takes effect as a `:root` variable.
|
|
55
|
+
* Tailwind folds shadows into classes (`.shadow-md { --tw-shadow: … }`), so `--tw-shadow` is overridden per class
|
|
56
|
+
*/
|
|
57
|
+
function toRuntimeCss(tuning, catalog) {
|
|
58
|
+
const n = normalize(tuning, catalog);
|
|
59
|
+
const touched = touchedColors(n, catalog);
|
|
60
|
+
const root = [];
|
|
61
|
+
const dark = [];
|
|
62
|
+
for (const name of touched) {
|
|
63
|
+
root.push(decl(name, colorValue(n, catalog, "light", name)));
|
|
64
|
+
if (catalog.colors.find((color) => color.name === name)?.hasDark === true) dark.push(decl(name, colorValue(n, catalog, "dark", name)));
|
|
65
|
+
}
|
|
66
|
+
for (const [name, ref] of Object.entries(n.semantic)) root.push(decl(name, `var(--${ref})`));
|
|
67
|
+
for (const [name, value] of radiusRoles(n)) root.push(decl(name, value));
|
|
68
|
+
for (const key of FONT_KEYS) {
|
|
69
|
+
const value = n.font[key];
|
|
70
|
+
if (value !== void 0) root.push(decl(FONT_TOKEN[key], value));
|
|
71
|
+
}
|
|
72
|
+
if (n.font.bodySize !== void 0) {
|
|
73
|
+
root.push(decl("text-body", `${n.font.bodySize}px`));
|
|
74
|
+
root.push(decl("text-body--line-height", `${bodyLineHeight(catalog, n.font.bodySize)}px`));
|
|
75
|
+
}
|
|
76
|
+
const parts = [block(":root", root), block(".dark", dark)];
|
|
77
|
+
for (const [step, value] of shadowValues(n)) parts.push(block(`.shadow-${step}`, [` --tw-shadow: ${value};`]));
|
|
78
|
+
return parts.filter((part) => part !== "").join("\n");
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* **The CSS for copying.** The same format as `styles.gen.css`, with only the difference from the defaults (`:root` / `.dark` / `@theme`).
|
|
82
|
+
* `@theme` holds Tailwind build-time variables (radius, shadow, body size), which `styles.gen.css` emits from the `theme` in `definition.ts`.
|
|
83
|
+
* It is separate from the CSS applied at runtime (`toRuntimeCss`; that one cannot use `@theme`).
|
|
84
|
+
*/
|
|
85
|
+
function toExportCss(tuning, catalog) {
|
|
86
|
+
const n = normalize(tuning, catalog);
|
|
87
|
+
const root = [];
|
|
88
|
+
const dark = [];
|
|
89
|
+
for (const color of catalog.colors) {
|
|
90
|
+
const light = n.tokens.light[color.name];
|
|
91
|
+
if (light !== void 0) root.push(decl(color.name, light));
|
|
92
|
+
const night = n.tokens.dark[color.name];
|
|
93
|
+
if (night !== void 0) dark.push(decl(color.name, night));
|
|
94
|
+
}
|
|
95
|
+
for (const [name, ref] of Object.entries(n.semantic)) root.push(decl(name, `var(--${ref})`));
|
|
96
|
+
for (const key of FONT_KEYS) {
|
|
97
|
+
const value = n.font[key];
|
|
98
|
+
if (value !== void 0) root.push(decl(FONT_TOKEN[key], value));
|
|
99
|
+
}
|
|
100
|
+
const theme = radiusRoles(n).map(([name, value]) => decl(name, value));
|
|
101
|
+
for (const [step, value] of shadowValues(n)) theme.push(decl(`shadow-${step}`, value));
|
|
102
|
+
if (n.font.bodySize !== void 0) {
|
|
103
|
+
theme.push(decl("text-body", `${n.font.bodySize}px`));
|
|
104
|
+
theme.push(decl("text-body--line-height", `${bodyLineHeight(catalog, n.font.bodySize)}px`));
|
|
105
|
+
}
|
|
106
|
+
return [
|
|
107
|
+
block(":root", root),
|
|
108
|
+
block(".dark", dark),
|
|
109
|
+
block("@theme", theme)
|
|
110
|
+
].filter((part) => part !== "").join("\n\n");
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* **The diff to bring into `definition.ts`.** In the shape of the SSOT token lines (`{ name, value, dark }`) and the `theme` lines,
|
|
114
|
+
* it outputs only the changed items. Names stay the same and only values are swapped (how to edit tokens). Run `bun run generate` after bringing it in.
|
|
115
|
+
*/
|
|
116
|
+
function toDefinitionDiff(tuning, catalog) {
|
|
117
|
+
const n = normalize(tuning, catalog);
|
|
118
|
+
const lines = [];
|
|
119
|
+
const tokenLines = [];
|
|
120
|
+
for (const color of catalog.colors) {
|
|
121
|
+
if (n.tokens.light[color.name] === void 0 && n.tokens.dark[color.name] === void 0) continue;
|
|
122
|
+
const fields = [`name: ${JSON.stringify(color.name)}`, `value: ${JSON.stringify(colorValue(n, catalog, "light", color.name))}`];
|
|
123
|
+
if (color.hasDark) fields.push(`dark: ${JSON.stringify(colorValue(n, catalog, "dark", color.name))}`);
|
|
124
|
+
fields.push("color: true");
|
|
125
|
+
tokenLines.push(`{ ${fields.join(", ")} },`);
|
|
126
|
+
}
|
|
127
|
+
for (const [name, ref] of Object.entries(n.semantic)) tokenLines.push(`{ name: ${JSON.stringify(name)}, value: ${JSON.stringify(`var(--${ref})`)}, color: true },`);
|
|
128
|
+
for (const key of FONT_KEYS) {
|
|
129
|
+
const value = n.font[key];
|
|
130
|
+
if (value !== void 0) tokenLines.push(`{ name: ${JSON.stringify(FONT_TOKEN[key])}, value: ${JSON.stringify(value)} },`);
|
|
131
|
+
}
|
|
132
|
+
if (tokenLines.length > 0) lines.push("// groups[].tokens の該当する行を、次の値に差し替える", ...tokenLines);
|
|
133
|
+
const themeLines = radiusRoles(n).map(([name, value]) => `${JSON.stringify(name)}: ${JSON.stringify(value)},`);
|
|
134
|
+
for (const [step, value] of shadowValues(n)) themeLines.push(`${JSON.stringify(`shadow-${step}`)}: ${JSON.stringify(value)},`);
|
|
135
|
+
if (n.font.bodySize !== void 0) {
|
|
136
|
+
themeLines.push(`"text-body": ${JSON.stringify(`${n.font.bodySize}px`)},`);
|
|
137
|
+
themeLines.push(`"text-body--line-height": ${JSON.stringify(`${bodyLineHeight(catalog, n.font.bodySize)}px`)},`);
|
|
138
|
+
}
|
|
139
|
+
if (themeLines.length > 0) {
|
|
140
|
+
if (lines.length > 0) lines.push("");
|
|
141
|
+
lines.push("// theme の該当する行を、次の値に差し替える", ...themeLines);
|
|
142
|
+
}
|
|
143
|
+
return lines.join("\n");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
export { SHADOW_PRESET, toDefinitionDiff, toExportCss, toRuntimeCss };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BODY_SIZE_MAX, BODY_SIZE_MIN, ColorGroup, ColorToken, FONT_KEYS, FONT_TOKEN, FontKey, MODES, Mode, RADIUS_MAX, RADIUS_ROLES, RadiusRole, ShadowPreset, Tuning, TuningCatalog, emptyTuning } from "./types.js";
|
|
2
|
+
import { buildCatalog, buildCatalogSafe, findColor } from "./catalog.js";
|
|
3
|
+
import { ColorResult, parseTokenColor } from "./color.js";
|
|
4
|
+
import { SHADOW_PRESET, toDefinitionDiff, toExportCss, toRuntimeCss } from "./css.js";
|
|
5
|
+
import { bodyLineHeight, colorValue, countChanges, defaultFont, effectiveTokens, isEmpty, modeOf, normalize, radiusPx, withBodySize, withColor, withFont, withRadius, withSemantic, withShadow } from "./model.js";
|
|
6
|
+
import { NATIVE_BUILD_FIXED_BRAND_TOKENS, NATIVE_BUILD_FIXED_TOKENS, firstFontFamily, nativeLimits, toNativeVariables } from "./native.js";
|
|
7
|
+
import { Envelope, FORMAT, MAX_ENTRIES, MAX_IMPORT_BYTES, MAX_REASONS, ParseResult, STORAGE_KEY, TOO_LARGE_REASON, VERSION, fontProblem, parseTuning, toExportObject, toJson, tooLarge } from "./schema.js";
|
|
8
|
+
export { BODY_SIZE_MAX, BODY_SIZE_MIN, ColorGroup, ColorResult, ColorToken, type Envelope, FONT_KEYS, FONT_TOKEN, FORMAT, FontKey, MAX_ENTRIES, MAX_IMPORT_BYTES, MAX_REASONS, MODES, Mode, NATIVE_BUILD_FIXED_BRAND_TOKENS, NATIVE_BUILD_FIXED_TOKENS, ParseResult, RADIUS_MAX, RADIUS_ROLES, RadiusRole, SHADOW_PRESET, STORAGE_KEY, ShadowPreset, TOO_LARGE_REASON, Tuning, TuningCatalog, VERSION, bodyLineHeight, buildCatalog, buildCatalogSafe, colorValue, countChanges, defaultFont, effectiveTokens, emptyTuning, findColor, firstFontFamily, fontProblem, isEmpty, modeOf, nativeLimits, normalize, parseTokenColor, parseTuning, radiusPx, toDefinitionDiff, toExportCss, toExportObject, toJson, toNativeVariables, toRuntimeCss, tooLarge, withBodySize, withColor, withFont, withRadius, withSemantic, withShadow };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { buildCatalog, buildCatalogSafe, findColor } from "./catalog.js";
|
|
2
|
+
import { parseTokenColor } from "./color.js";
|
|
3
|
+
import { BODY_SIZE_MAX, BODY_SIZE_MIN, FONT_KEYS, FONT_TOKEN, MODES, RADIUS_MAX, RADIUS_ROLES, emptyTuning } from "./types.js";
|
|
4
|
+
import { bodyLineHeight, colorValue, countChanges, defaultFont, effectiveTokens, isEmpty, modeOf, normalize, radiusPx, withBodySize, withColor, withFont, withRadius, withSemantic, withShadow } from "./model.js";
|
|
5
|
+
import { SHADOW_PRESET, toDefinitionDiff, toExportCss, toRuntimeCss } from "./css.js";
|
|
6
|
+
import { NATIVE_BUILD_FIXED_BRAND_TOKENS, NATIVE_BUILD_FIXED_TOKENS, firstFontFamily, nativeLimits, toNativeVariables } from "./native.js";
|
|
7
|
+
import { FORMAT, MAX_ENTRIES, MAX_IMPORT_BYTES, MAX_REASONS, STORAGE_KEY, TOO_LARGE_REASON, VERSION, fontProblem, parseTuning, toExportObject, toJson, tooLarge } from "./schema.js";
|
|
8
|
+
|
|
9
|
+
export { BODY_SIZE_MAX, BODY_SIZE_MIN, FONT_KEYS, FONT_TOKEN, FORMAT, MAX_ENTRIES, MAX_IMPORT_BYTES, MAX_REASONS, MODES, NATIVE_BUILD_FIXED_BRAND_TOKENS, NATIVE_BUILD_FIXED_TOKENS, RADIUS_MAX, RADIUS_ROLES, SHADOW_PRESET, STORAGE_KEY, TOO_LARGE_REASON, VERSION, bodyLineHeight, buildCatalog, buildCatalogSafe, colorValue, countChanges, defaultFont, effectiveTokens, emptyTuning, findColor, firstFontFamily, fontProblem, isEmpty, modeOf, nativeLimits, normalize, parseTokenColor, parseTuning, radiusPx, toDefinitionDiff, toExportCss, toExportObject, toJson, toNativeVariables, toRuntimeCss, tooLarge, withBodySize, withColor, withFont, withRadius, withSemantic, withShadow };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { FontKey, Mode, RadiusRole, ShadowPreset, Tuning, TuningCatalog } from "./types.js";
|
|
2
|
+
//#region src/tuning/model.d.ts
|
|
3
|
+
/** The mode that actually holds a color token. Brand colors are common to both, so a dark specification is folded into `light`. */
|
|
4
|
+
export declare function modeOf(catalog: TuningCatalog, name: string, mode: Mode): Mode;
|
|
5
|
+
/** The default font value. */
|
|
6
|
+
export declare function defaultFont(catalog: TuningCatalog, key: FontKey): string;
|
|
7
|
+
/** The radius (px) per role. Falls back to the default (control 6, surface 10) when unspecified. */
|
|
8
|
+
export declare function radiusPx(tuning: Tuning, catalog: TuningCatalog, role: RadiusRole): number;
|
|
9
|
+
/** The body line height (px). Proportional to the size (the ratio of the default 14px / 22px). */
|
|
10
|
+
export declare function bodyLineHeight(catalog: TuningCatalog, size: number): number;
|
|
11
|
+
/**
|
|
12
|
+
* Drops items equal to the defaults so that the same content has a single form (run before saving, exporting, and comparing).
|
|
13
|
+
* Colors are aligned to the canonical form (lowercase `#rrggbb`). Unreadable colors are kept as they are (validation is the job of `parseTuning`).
|
|
14
|
+
*/
|
|
15
|
+
export declare function normalize(tuning: Tuning, catalog: TuningCatalog): Tuning;
|
|
16
|
+
/** Whether it equals the defaults (has no difference). */
|
|
17
|
+
export declare function isEmpty(tuning: Tuning, catalog: TuningCatalog): boolean;
|
|
18
|
+
/** The number of differences from the defaults (1 per item of color, reference, radius, typeface, and shadow). */
|
|
19
|
+
export declare function countChanges(tuning: Tuning, catalog: TuningCatalog): number;
|
|
20
|
+
/**
|
|
21
|
+
* The actual value of a token. **It follows references (`var()`)**: a semantic token takes the actual value of its target (the override if there is one, the default otherwise).
|
|
22
|
+
* If you tune the ramp it refers to, the semantic tokens pointing at it change too (resolved the same way as the runtime CSS).
|
|
23
|
+
*/
|
|
24
|
+
export declare function colorValue(tuning: Tuning, catalog: TuningCatalog, mode: Mode, name: string): string;
|
|
25
|
+
/** A table of the actual values of all tokens (color, typeface, tuned radius). The values after the tuning is applied, in the same shape as `tokens`. */
|
|
26
|
+
export declare function effectiveTokens(tuning: Tuning, catalog: TuningCatalog): Record<Mode, Record<string, string>>;
|
|
27
|
+
export declare function withColor(tuning: Tuning, catalog: TuningCatalog, mode: Mode, name: string, value: string | undefined): Tuning;
|
|
28
|
+
export declare function withSemantic(tuning: Tuning, name: string, ref: string | undefined): Tuning;
|
|
29
|
+
export declare function withRadius(tuning: Tuning, role: RadiusRole, px: number | undefined): Tuning;
|
|
30
|
+
export declare function withFont(tuning: Tuning, key: FontKey, value: string | undefined): Tuning;
|
|
31
|
+
export declare function withBodySize(tuning: Tuning, size: number | undefined): Tuning;
|
|
32
|
+
export declare function withShadow(tuning: Tuning, shadow: ShadowPreset): Tuning;
|
|
33
|
+
//#endregion
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { parseTokenColor } from "./color.js";
|
|
2
|
+
import { FONT_KEYS, FONT_TOKEN, MODES, RADIUS_ROLES, emptyTuning } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/tuning/model.ts
|
|
5
|
+
/** The mode that actually holds a color token. Brand colors are common to both, so a dark specification is folded into `light`. */
|
|
6
|
+
function modeOf(catalog, name, mode) {
|
|
7
|
+
return mode === "dark" && catalog.colors.find((color) => color.name === name)?.hasDark === false ? "light" : mode;
|
|
8
|
+
}
|
|
9
|
+
/** The default font value. */
|
|
10
|
+
function defaultFont(catalog, key) {
|
|
11
|
+
return catalog.defaults.light[FONT_TOKEN[key]] ?? "";
|
|
12
|
+
}
|
|
13
|
+
/** The radius (px) per role. Falls back to the default (control 6, surface 10) when unspecified. */
|
|
14
|
+
function radiusPx(tuning, catalog, role) {
|
|
15
|
+
return tuning.radius[role] ?? catalog.radius[role];
|
|
16
|
+
}
|
|
17
|
+
/** The body line height (px). Proportional to the size (the ratio of the default 14px / 22px). */
|
|
18
|
+
function bodyLineHeight(catalog, size) {
|
|
19
|
+
return Math.round(size * catalog.body.lineHeight / catalog.body.size);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Drops items equal to the defaults so that the same content has a single form (run before saving, exporting, and comparing).
|
|
23
|
+
* Colors are aligned to the canonical form (lowercase `#rrggbb`). Unreadable colors are kept as they are (validation is the job of `parseTuning`).
|
|
24
|
+
*/
|
|
25
|
+
function normalize(tuning, catalog) {
|
|
26
|
+
const out = emptyTuning();
|
|
27
|
+
for (const mode of MODES) for (const color of catalog.colors) {
|
|
28
|
+
const raw = tuning.tokens[mode][color.name];
|
|
29
|
+
if (raw === void 0) continue;
|
|
30
|
+
if (mode === "dark" && !color.hasDark) continue;
|
|
31
|
+
const parsed = parseTokenColor(raw, { alpha: color.alpha });
|
|
32
|
+
const value = parsed.ok ? parsed.value : raw;
|
|
33
|
+
const fallback = catalog.defaults[mode][color.name];
|
|
34
|
+
if (value !== (fallback === void 0 ? void 0 : toCanonical(fallback, color.alpha))) out.tokens[mode][color.name] = value;
|
|
35
|
+
}
|
|
36
|
+
for (const [name, ref] of Object.entries(tuning.semantic)) if (Object.hasOwn(catalog.semantic, name) && ref !== catalog.semantic[name]) out.semantic[name] = ref;
|
|
37
|
+
for (const role of RADIUS_ROLES) {
|
|
38
|
+
const px = tuning.radius[role];
|
|
39
|
+
if (px !== void 0 && px !== catalog.radius[role]) out.radius[role] = px;
|
|
40
|
+
}
|
|
41
|
+
for (const key of FONT_KEYS) {
|
|
42
|
+
const value = tuning.font[key];
|
|
43
|
+
if (value !== void 0 && value !== defaultFont(catalog, key)) out.font[key] = value;
|
|
44
|
+
}
|
|
45
|
+
if (tuning.font.bodySize !== void 0 && tuning.font.bodySize !== catalog.body.size) out.font.bodySize = tuning.font.bodySize;
|
|
46
|
+
out.shadow = tuning.shadow;
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function toCanonical(value, alpha) {
|
|
50
|
+
const parsed = parseTokenColor(value, { alpha });
|
|
51
|
+
return parsed.ok ? parsed.value : value;
|
|
52
|
+
}
|
|
53
|
+
/** Whether it equals the defaults (has no difference). */
|
|
54
|
+
function isEmpty(tuning, catalog) {
|
|
55
|
+
return countChanges(tuning, catalog) === 0;
|
|
56
|
+
}
|
|
57
|
+
/** The number of differences from the defaults (1 per item of color, reference, radius, typeface, and shadow). */
|
|
58
|
+
function countChanges(tuning, catalog) {
|
|
59
|
+
const n = normalize(tuning, catalog);
|
|
60
|
+
return Object.keys(n.tokens.light).length + Object.keys(n.tokens.dark).length + Object.keys(n.semantic).length + Object.keys(n.radius).length + Object.keys(n.font).length + (n.shadow === "default" ? 0 : 1);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The actual value of a token. **It follows references (`var()`)**: a semantic token takes the actual value of its target (the override if there is one, the default otherwise).
|
|
64
|
+
* If you tune the ramp it refers to, the semantic tokens pointing at it change too (resolved the same way as the runtime CSS).
|
|
65
|
+
*/
|
|
66
|
+
function colorValue(tuning, catalog, mode, name) {
|
|
67
|
+
const ref = (Object.hasOwn(tuning.semantic, name) ? tuning.semantic[name] : void 0) ?? (Object.hasOwn(catalog.semantic, name) ? catalog.semantic[name] : void 0);
|
|
68
|
+
if (ref !== void 0) return colorValue(tuning, catalog, mode, ref);
|
|
69
|
+
const owner = modeOf(catalog, name, mode);
|
|
70
|
+
const override = Object.hasOwn(tuning.tokens[owner], name) ? tuning.tokens[owner][name] : void 0;
|
|
71
|
+
if (override !== void 0) return override;
|
|
72
|
+
const fallback = Object.hasOwn(catalog.defaults[mode], name) ? catalog.defaults[mode][name] : void 0;
|
|
73
|
+
if (fallback === void 0) throw new Error(`未定義のトークン: --${name}`);
|
|
74
|
+
return fallback;
|
|
75
|
+
}
|
|
76
|
+
/** A table of the actual values of all tokens (color, typeface, tuned radius). The values after the tuning is applied, in the same shape as `tokens`. */
|
|
77
|
+
function effectiveTokens(tuning, catalog) {
|
|
78
|
+
const out = {
|
|
79
|
+
light: {},
|
|
80
|
+
dark: {}
|
|
81
|
+
};
|
|
82
|
+
for (const mode of MODES) {
|
|
83
|
+
for (const [name, value] of Object.entries(catalog.defaults[mode])) {
|
|
84
|
+
const isColor = catalog.colors.some((color) => color.name === name) || Object.hasOwn(catalog.semantic, name);
|
|
85
|
+
out[mode][name] = isColor ? colorValue(tuning, catalog, mode, name) : value;
|
|
86
|
+
}
|
|
87
|
+
for (const key of FONT_KEYS) out[mode][FONT_TOKEN[key]] = tuning.font[key] ?? defaultFont(catalog, key);
|
|
88
|
+
out[mode]["font-mono"] = out[mode]["font-geist-mono"] ?? "";
|
|
89
|
+
for (const role of RADIUS_ROLES) {
|
|
90
|
+
const px = tuning.radius[role];
|
|
91
|
+
if (px !== void 0) out[mode][`radius-${role}`] = `${px}px`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
function withColor(tuning, catalog, mode, name, value) {
|
|
97
|
+
const owner = modeOf(catalog, name, mode);
|
|
98
|
+
const table = { ...tuning.tokens[owner] };
|
|
99
|
+
if (value === void 0) delete table[name];
|
|
100
|
+
else table[name] = value;
|
|
101
|
+
return {
|
|
102
|
+
...tuning,
|
|
103
|
+
tokens: {
|
|
104
|
+
...tuning.tokens,
|
|
105
|
+
[owner]: table
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function withSemantic(tuning, name, ref) {
|
|
110
|
+
const semantic = { ...tuning.semantic };
|
|
111
|
+
if (ref === void 0) delete semantic[name];
|
|
112
|
+
else semantic[name] = ref;
|
|
113
|
+
return {
|
|
114
|
+
...tuning,
|
|
115
|
+
semantic
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function withRadius(tuning, role, px) {
|
|
119
|
+
const radius = { ...tuning.radius };
|
|
120
|
+
if (px === void 0) delete radius[role];
|
|
121
|
+
else radius[role] = px;
|
|
122
|
+
return {
|
|
123
|
+
...tuning,
|
|
124
|
+
radius
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function withFont(tuning, key, value) {
|
|
128
|
+
const font = { ...tuning.font };
|
|
129
|
+
if (value === void 0) delete font[key];
|
|
130
|
+
else font[key] = value;
|
|
131
|
+
return {
|
|
132
|
+
...tuning,
|
|
133
|
+
font
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function withBodySize(tuning, size) {
|
|
137
|
+
const { bodySize: _previous, ...rest } = tuning.font;
|
|
138
|
+
return {
|
|
139
|
+
...tuning,
|
|
140
|
+
font: size === void 0 ? rest : {
|
|
141
|
+
...rest,
|
|
142
|
+
bodySize: size
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function withShadow(tuning, shadow) {
|
|
147
|
+
return {
|
|
148
|
+
...tuning,
|
|
149
|
+
shadow
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
export { bodyLineHeight, colorValue, countChanges, defaultFont, effectiveTokens, isEmpty, modeOf, normalize, radiusPx, withBodySize, withColor, withFont, withRadius, withSemantic, withShadow };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Mode, Tuning, TuningCatalog } from "./types.js";
|
|
2
|
+
//#region src/tuning/native.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Tokens with the **same value** in light and dark (not redefined in `.dark`), and the aliases pointing at them.
|
|
5
|
+
* react-native-css **folds a variable declared only once into a literal at build time**, so classes such as `bg-action`
|
|
6
|
+
* do not read a CSS variable on a real device and **do not follow runtime overrides (`toNativeVariables`)**. `useTokenColor`, which reads colors from TS, does follow them.
|
|
7
|
+
* `native/lib/tokens.test.ts` checks that the list does not drift from `definition.ts`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const NATIVE_BUILD_FIXED_TOKENS: readonly ["action", "action-hover", "action-foreground", "primary", "primary-foreground", "ring", "sidebar-primary", "sidebar-primary-foreground", "sidebar-ring", "destructive-solid-foreground"];
|
|
10
|
+
/**
|
|
11
|
+
* The brand colors (`lt-three`, `lt-three-foreground`). They are common to light and dark and fixed at build time, so classes such as `bg-lt-three`
|
|
12
|
+
* do not follow runtime overrides (by design, so that they do not invert with the theme). They are kept apart from `NATIVE_BUILD_FIXED_TOKENS`
|
|
13
|
+
* because the folding check in `native/lib/tokens-check.ts` treats brand colors separately (so the list check does not drift).
|
|
14
|
+
*/
|
|
15
|
+
export declare const NATIVE_BUILD_FIXED_BRAND_TOKENS: readonly ["lt-three", "lt-three-foreground"];
|
|
16
|
+
/** The first name in a typeface value (a CSS font-family list). RN's `fontFamily` takes only one name. undefined for `var()`. */
|
|
17
|
+
export declare function firstFontFamily(value: string): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* The CSS variables handed to native (the `value` of react-native-css's `VariableContextProvider`). For the given mode, **only those that differ from the defaults**.
|
|
20
|
+
* - Color tokens: effective values (with semantic references resolved). Semantic tokens that depend on a changed ramp are also emitted
|
|
21
|
+
* as separate literals under the same change (in react-native-web, `--card: var(--raised)` is already resolved at `:root` and does not follow an override of the ramp alone)
|
|
22
|
+
* - Radius (`--radius-control` / `--radius-surface`): px
|
|
23
|
+
* - Typeface (`--font-geist` and so on): only the first name
|
|
24
|
+
*
|
|
25
|
+
* **What takes effect on a real device is classes that use color tokens with different values in light and dark (such as `bg-card`; on a real device they become references to the ramp) and the typeface**.
|
|
26
|
+
* Radius and body size are folded into literals at build time, and the color classes of `NATIVE_BUILD_FIXED_TOKENS` are folded too, so they have no effect on a real device
|
|
27
|
+
* (in react-native-web they are CSS variables and do take effect). `nativeLimits` returns what has no effect.
|
|
28
|
+
*/
|
|
29
|
+
export declare function toNativeVariables(tuning: Tuning, catalog: TuningCatalog, mode: Mode): Record<`--${string}`, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Descriptions (in Japanese) of the tuning items that **have no effect at runtime on a real native device**. Empty means everything takes effect (everything does in react-native-web).
|
|
32
|
+
* They are shown on the tuning screen so that it is clear the lack of effect is by design. The values stay in the JSON, so they take effect when read on web.
|
|
33
|
+
*/
|
|
34
|
+
export declare function nativeLimits(tuning: Tuning, catalog: TuningCatalog): string[];
|
|
35
|
+
//#endregion
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { FONT_KEYS, FONT_TOKEN, RADIUS_ROLES } from "./types.js";
|
|
2
|
+
import { effectiveTokens, normalize } from "./model.js";
|
|
3
|
+
|
|
4
|
+
//#region src/tuning/native.ts
|
|
5
|
+
/**
|
|
6
|
+
* Tokens with the **same value** in light and dark (not redefined in `.dark`), and the aliases pointing at them.
|
|
7
|
+
* react-native-css **folds a variable declared only once into a literal at build time**, so classes such as `bg-action`
|
|
8
|
+
* do not read a CSS variable on a real device and **do not follow runtime overrides (`toNativeVariables`)**. `useTokenColor`, which reads colors from TS, does follow them.
|
|
9
|
+
* `native/lib/tokens.test.ts` checks that the list does not drift from `definition.ts`.
|
|
10
|
+
*/
|
|
11
|
+
const NATIVE_BUILD_FIXED_TOKENS = [
|
|
12
|
+
"action",
|
|
13
|
+
"action-hover",
|
|
14
|
+
"action-foreground",
|
|
15
|
+
"primary",
|
|
16
|
+
"primary-foreground",
|
|
17
|
+
"ring",
|
|
18
|
+
"sidebar-primary",
|
|
19
|
+
"sidebar-primary-foreground",
|
|
20
|
+
"sidebar-ring",
|
|
21
|
+
"destructive-solid-foreground"
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* The brand colors (`lt-three`, `lt-three-foreground`). They are common to light and dark and fixed at build time, so classes such as `bg-lt-three`
|
|
25
|
+
* do not follow runtime overrides (by design, so that they do not invert with the theme). They are kept apart from `NATIVE_BUILD_FIXED_TOKENS`
|
|
26
|
+
* because the folding check in `native/lib/tokens-check.ts` treats brand colors separately (so the list check does not drift).
|
|
27
|
+
*/
|
|
28
|
+
const NATIVE_BUILD_FIXED_BRAND_TOKENS = ["lt-three", "lt-three-foreground"];
|
|
29
|
+
/** The first name in a typeface value (a CSS font-family list). RN's `fontFamily` takes only one name. undefined for `var()`. */
|
|
30
|
+
function firstFontFamily(value) {
|
|
31
|
+
const first = value.split(",")[0]?.trim() ?? "";
|
|
32
|
+
if (first === "" || first.startsWith("var(")) return void 0;
|
|
33
|
+
return first.replace(/^["']|["']$/g, "");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The CSS variables handed to native (the `value` of react-native-css's `VariableContextProvider`). For the given mode, **only those that differ from the defaults**.
|
|
37
|
+
* - Color tokens: effective values (with semantic references resolved). Semantic tokens that depend on a changed ramp are also emitted
|
|
38
|
+
* as separate literals under the same change (in react-native-web, `--card: var(--raised)` is already resolved at `:root` and does not follow an override of the ramp alone)
|
|
39
|
+
* - Radius (`--radius-control` / `--radius-surface`): px
|
|
40
|
+
* - Typeface (`--font-geist` and so on): only the first name
|
|
41
|
+
*
|
|
42
|
+
* **What takes effect on a real device is classes that use color tokens with different values in light and dark (such as `bg-card`; on a real device they become references to the ramp) and the typeface**.
|
|
43
|
+
* Radius and body size are folded into literals at build time, and the color classes of `NATIVE_BUILD_FIXED_TOKENS` are folded too, so they have no effect on a real device
|
|
44
|
+
* (in react-native-web they are CSS variables and do take effect). `nativeLimits` returns what has no effect.
|
|
45
|
+
*/
|
|
46
|
+
function toNativeVariables(tuning, catalog, mode) {
|
|
47
|
+
const n = normalize(tuning, catalog);
|
|
48
|
+
const effective = effectiveTokens(n, catalog)[mode];
|
|
49
|
+
const out = {};
|
|
50
|
+
const isColor = (name) => catalog.colors.some((color) => color.name === name) || Object.hasOwn(catalog.semantic, name);
|
|
51
|
+
for (const [name, value] of Object.entries(effective)) if (isColor(name) && value !== catalog.defaults[mode][name]) out[`--${name}`] = value;
|
|
52
|
+
for (const role of RADIUS_ROLES) {
|
|
53
|
+
const px = n.radius[role];
|
|
54
|
+
if (px !== void 0) out[`--radius-${role}`] = `${px}px`;
|
|
55
|
+
}
|
|
56
|
+
for (const key of FONT_KEYS) {
|
|
57
|
+
const family = n.font[key] === void 0 ? void 0 : firstFontFamily(n.font[key]);
|
|
58
|
+
if (family !== void 0) out[`--${FONT_TOKEN[key]}`] = family;
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Descriptions (in Japanese) of the tuning items that **have no effect at runtime on a real native device**. Empty means everything takes effect (everything does in react-native-web).
|
|
64
|
+
* They are shown on the tuning screen so that it is clear the lack of effect is by design. The values stay in the JSON, so they take effect when read on web.
|
|
65
|
+
*/
|
|
66
|
+
function nativeLimits(tuning, catalog) {
|
|
67
|
+
const n = normalize(tuning, catalog);
|
|
68
|
+
const notes = [];
|
|
69
|
+
const fixed = /* @__PURE__ */ new Set([...NATIVE_BUILD_FIXED_TOKENS, ...NATIVE_BUILD_FIXED_BRAND_TOKENS]);
|
|
70
|
+
const touched = [.../* @__PURE__ */ new Set([...Object.keys(n.tokens.light), ...Object.keys(n.tokens.dark)])].filter((name) => fixed.has(name));
|
|
71
|
+
if (touched.length > 0) notes.push(`${touched.map((name) => `--${name}`).join("・")} は、実機ではビルド時に固定されるクラス(bg-action など)に効きません(TS から色を引く部品には効きます)`);
|
|
72
|
+
if (Object.keys(n.semantic).length > 0) notes.push("セマンティックトークンの参照先の変更は、実機ではクラスに効きません(ビルド時にランプへ解決されるため)");
|
|
73
|
+
if (Object.keys(n.radius).length > 0) notes.push("角丸は、実機ではビルド時に固定されるので効きません");
|
|
74
|
+
if (n.font.bodySize !== void 0) notes.push("本文サイズは、実機ではビルド時に固定されるので効きません");
|
|
75
|
+
if (n.shadow !== "default") notes.push("影の preset は native には適用しません");
|
|
76
|
+
return notes;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { NATIVE_BUILD_FIXED_BRAND_TOKENS, NATIVE_BUILD_FIXED_TOKENS, firstFontFamily, nativeLimits, toNativeVariables };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Tuning, TuningCatalog } from "./types.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/tuning/schema.d.ts
|
|
4
|
+
/** The name and version of the export and save format. Bump `VERSION` when the shape changes. */
|
|
5
|
+
export declare const FORMAT = "love3-tuning";
|
|
6
|
+
export declare const VERSION = 1;
|
|
7
|
+
/** The key of the storage location (localStorage). */
|
|
8
|
+
export declare const STORAGE_KEY = "love3-preview:tuning";
|
|
9
|
+
/**
|
|
10
|
+
* The skeleton of the format. **Unknown fields are rejected** (`strictObject`). Checks that depend on the design system, such as token names and color contents, are added by `parseTuning`.
|
|
11
|
+
* Every field can be omitted (write only the difference from the defaults).
|
|
12
|
+
*/
|
|
13
|
+
declare const envelope: z.ZodObject<{
|
|
14
|
+
format: z.ZodLiteral<"love3-tuning">;
|
|
15
|
+
version: z.ZodLiteral<1>;
|
|
16
|
+
tokens: z.ZodOptional<z.ZodObject<{
|
|
17
|
+
light: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
18
|
+
dark: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
19
|
+
}, z.core.$strict>>;
|
|
20
|
+
radius: z.ZodOptional<z.ZodObject<{
|
|
21
|
+
control: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
surface: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
}, z.core.$strict>>;
|
|
24
|
+
semantic: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
25
|
+
font: z.ZodOptional<z.ZodObject<{
|
|
26
|
+
geist: z.ZodOptional<z.ZodString>;
|
|
27
|
+
geistMono: z.ZodOptional<z.ZodString>;
|
|
28
|
+
jp: z.ZodOptional<z.ZodString>;
|
|
29
|
+
bodySize: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
}, z.core.$strict>>;
|
|
31
|
+
shadow: z.ZodOptional<z.ZodEnum<{
|
|
32
|
+
default: "default";
|
|
33
|
+
none: "none";
|
|
34
|
+
preset: "preset";
|
|
35
|
+
}>>;
|
|
36
|
+
}, z.core.$strict>;
|
|
37
|
+
type Envelope = z.output<typeof envelope>;
|
|
38
|
+
/** The upper limit of the size of an imported JSON (bytes), for both pasting and files. */
|
|
39
|
+
export declare const MAX_IMPORT_BYTES: number;
|
|
40
|
+
/** The upper limit of the number of entries in one table (`tokens.light` / `tokens.dark` / `semantic`). There are fewer than 50 names that can be tuned. */
|
|
41
|
+
export declare const MAX_ENTRIES = 200;
|
|
42
|
+
/** Lists rejection reasons up to this many (the rest become "N more"). */
|
|
43
|
+
export declare const MAX_REASONS = 20;
|
|
44
|
+
/** Whether the text being imported exceeds the limit (`MAX_IMPORT_BYTES`). */
|
|
45
|
+
export declare function tooLarge(text: string): boolean;
|
|
46
|
+
export declare const TOO_LARGE_REASON = "大きすぎます(256 KB まで)";
|
|
47
|
+
export declare function fontProblem(value: string): string | undefined;
|
|
48
|
+
export type ParseResult = {
|
|
49
|
+
ok: true;
|
|
50
|
+
tuning: Tuning;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
reasons: string[];
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Reads and validates an exported JSON (a string). **If anything is invalid, the whole input is rejected (no partial application).**
|
|
57
|
+
* The rejection reasons are all the problems found, in Japanese, each with the location of the item.
|
|
58
|
+
*
|
|
59
|
+
* What is rejected: unreadable JSON, a wrong `format` / `version`, unknown fields, unknown token names (`--name`),
|
|
60
|
+
* invalid colors, a dark specification for a token common to light and dark (brand colors), unknown semantic tokens, unselectable reference targets,
|
|
61
|
+
* out-of-range radius and body size, and typefaces that cannot be injected. On success, it returns the form with items equal to the defaults dropped (`normalize`).
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseTuning(text: string, catalog: TuningCatalog): ParseResult;
|
|
64
|
+
/** The object for export containing only the difference (empty sections are omitted). */
|
|
65
|
+
export declare function toExportObject(tuning: Tuning, catalog: TuningCatalog): Record<string, unknown>;
|
|
66
|
+
/** The JSON for export and saving (only the difference from the defaults; pretty-printed). */
|
|
67
|
+
export declare function toJson(tuning: Tuning, catalog: TuningCatalog): string;
|
|
68
|
+
//#endregion
|
|
69
|
+
export type { Envelope };
|