app-studio 0.7.10 → 0.7.12
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 +72 -10
- package/dist/app-studio.cjs.development.js +315 -263
- package/dist/app-studio.cjs.development.js.map +1 -1
- package/dist/app-studio.cjs.production.min.js +1 -1
- package/dist/app-studio.esm.js +315 -263
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +315 -263
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/element/Element.types.d.ts +1 -0
- package/dist/utils/vendorPrefixes.d.ts +12 -2
- package/docs/README.md +2 -1
- package/docs/Styling.md +571 -0
- package/docs/Theming.md +461 -0
- package/package.json +2 -1
package/docs/Theming.md
CHANGED
|
@@ -635,6 +635,236 @@ Each palette has these shades: `50, 100, 200, 300, 400, 500, 600, 700, 800, 900`
|
|
|
635
635
|
- Colors automatically switch based on `themeMode` unless using `light-*` or `dark-*` prefix
|
|
636
636
|
- Color values are inverted for dark mode (e.g., `color-white` becomes black in dark mode)
|
|
637
637
|
|
|
638
|
+
## Using Colors with State Modifiers
|
|
639
|
+
|
|
640
|
+
App-Studio allows you to define different colors for interactive states using underscore-prefixed state modifiers. These provide a clean, declarative way to style components based on user interaction.
|
|
641
|
+
|
|
642
|
+
### Available State Modifiers
|
|
643
|
+
|
|
644
|
+
**Interaction States**:
|
|
645
|
+
- `_hover` - Hover state (mouse over)
|
|
646
|
+
- `_active` - Active/pressed state
|
|
647
|
+
- `_focus` - Focus state (keyboard/click)
|
|
648
|
+
- `_visited` - Visited state (for links)
|
|
649
|
+
|
|
650
|
+
**Form States**:
|
|
651
|
+
- `_disabled` - Disabled state
|
|
652
|
+
- `_enabled` - Enabled state
|
|
653
|
+
- `_checked` - Checked state (radio/checkbox)
|
|
654
|
+
- `_unchecked` - Unchecked state
|
|
655
|
+
- `_invalid` - Invalid form state
|
|
656
|
+
- `_valid` - Valid form state
|
|
657
|
+
- `_required` - Required form field
|
|
658
|
+
- `_optional` - Optional form field
|
|
659
|
+
|
|
660
|
+
**Element States**:
|
|
661
|
+
- `_selected` - Selected state
|
|
662
|
+
- `_target` - Target state (URL hash)
|
|
663
|
+
- `_empty` - Empty state
|
|
664
|
+
- `_focusVisible` - Visible focus (keyboard)
|
|
665
|
+
- `_focusWithin` - Focus within element
|
|
666
|
+
- `_placeholder` - Placeholder text state
|
|
667
|
+
|
|
668
|
+
**Child States**:
|
|
669
|
+
- `_firstChild` - First child element
|
|
670
|
+
- `_lastChild` - Last child element
|
|
671
|
+
- `_onlyChild` - Only child element
|
|
672
|
+
- `_firstOfType` - First of type element
|
|
673
|
+
- `_lastOfType` - Last of type element
|
|
674
|
+
|
|
675
|
+
**Group & Peer Modifiers**:
|
|
676
|
+
- `_groupHover` - Applied when parent `.group` is hovered
|
|
677
|
+
- `_groupFocus` - Applied when parent `.group` is focused
|
|
678
|
+
- `_groupActive` - Applied when parent `.group` is active
|
|
679
|
+
- `_groupDisabled` - Applied when parent `.group` is disabled
|
|
680
|
+
- `_peerHover` - Applied when sibling `.peer` is hovered
|
|
681
|
+
- `_peerFocus` - Applied when sibling `.peer` is focused
|
|
682
|
+
- `_peerActive` - Applied when sibling `.peer` is active
|
|
683
|
+
- `_peerDisabled` - Applied when sibling `.peer` is disabled
|
|
684
|
+
- `_peerChecked` - Applied when sibling `.peer` is checked
|
|
685
|
+
|
|
686
|
+
### Color Examples with State Modifiers
|
|
687
|
+
|
|
688
|
+
```javascript
|
|
689
|
+
import { View, Text, Element } from 'app-studio';
|
|
690
|
+
|
|
691
|
+
function InteractiveButton() {
|
|
692
|
+
return (
|
|
693
|
+
<Element
|
|
694
|
+
as="button"
|
|
695
|
+
backgroundColor="theme-primary"
|
|
696
|
+
color="color-white"
|
|
697
|
+
padding={16}
|
|
698
|
+
borderRadius={8}
|
|
699
|
+
cursor="pointer"
|
|
700
|
+
transition="all 200ms ease"
|
|
701
|
+
|
|
702
|
+
// Hover state - lighter color
|
|
703
|
+
_hover={{
|
|
704
|
+
backgroundColor: "theme-primary-600",
|
|
705
|
+
transform: "translateY(-2px)",
|
|
706
|
+
}}
|
|
707
|
+
|
|
708
|
+
// Active/pressed state - darker color
|
|
709
|
+
_active={{
|
|
710
|
+
backgroundColor: "theme-primary-700",
|
|
711
|
+
transform: "translateY(0)",
|
|
712
|
+
}}
|
|
713
|
+
|
|
714
|
+
// Focus state - add outline
|
|
715
|
+
_focus={{
|
|
716
|
+
outline: "2px solid",
|
|
717
|
+
outlineColor: "theme-primary",
|
|
718
|
+
outlineOffset: "2px",
|
|
719
|
+
}}
|
|
720
|
+
|
|
721
|
+
// Disabled state - gray out
|
|
722
|
+
_disabled={{
|
|
723
|
+
backgroundColor: "color-gray-400",
|
|
724
|
+
color: "color-gray-600",
|
|
725
|
+
cursor: "not-allowed",
|
|
726
|
+
opacity: 0.6,
|
|
727
|
+
}}
|
|
728
|
+
>
|
|
729
|
+
Click me
|
|
730
|
+
</Element>
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### Form Control Examples
|
|
736
|
+
|
|
737
|
+
```javascript
|
|
738
|
+
import { Element, View, Text } from 'app-studio';
|
|
739
|
+
|
|
740
|
+
function CheckboxExample() {
|
|
741
|
+
return (
|
|
742
|
+
<label style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
743
|
+
<Element
|
|
744
|
+
as="input"
|
|
745
|
+
type="checkbox"
|
|
746
|
+
// Default state
|
|
747
|
+
accentColor="theme-primary"
|
|
748
|
+
|
|
749
|
+
// Checked state - different color
|
|
750
|
+
_checked={{
|
|
751
|
+
accentColor: "theme-success",
|
|
752
|
+
}}
|
|
753
|
+
|
|
754
|
+
// Disabled state
|
|
755
|
+
_disabled={{
|
|
756
|
+
accentColor: "color-gray-400",
|
|
757
|
+
cursor: "not-allowed",
|
|
758
|
+
}}
|
|
759
|
+
|
|
760
|
+
// Focus state - add glow
|
|
761
|
+
_focus={{
|
|
762
|
+
boxShadow: "0 0 0 3px rgba(var(--theme-primary), 0.1)",
|
|
763
|
+
}}
|
|
764
|
+
/>
|
|
765
|
+
<Text color="color-gray-800">Accept terms</Text>
|
|
766
|
+
</label>
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
### Group Modifiers Example
|
|
772
|
+
|
|
773
|
+
Group modifiers allow you to style child elements based on parent state:
|
|
774
|
+
|
|
775
|
+
```javascript
|
|
776
|
+
import { View, Element } from 'app-studio';
|
|
777
|
+
|
|
778
|
+
function CardWithGroupHover() {
|
|
779
|
+
return (
|
|
780
|
+
<View
|
|
781
|
+
className="group"
|
|
782
|
+
backgroundColor="color-white"
|
|
783
|
+
borderRadius={12}
|
|
784
|
+
padding={16}
|
|
785
|
+
transition="all 200ms"
|
|
786
|
+
cursor="pointer"
|
|
787
|
+
|
|
788
|
+
// Parent hover
|
|
789
|
+
_hover={{
|
|
790
|
+
boxShadow: "0 10px 25px rgba(0,0,0,0.1)",
|
|
791
|
+
}}
|
|
792
|
+
>
|
|
793
|
+
{/* Child text changes color when parent is hovered */}
|
|
794
|
+
<Element
|
|
795
|
+
color="color-gray-600"
|
|
796
|
+
transition="color 200ms"
|
|
797
|
+
_groupHover={{
|
|
798
|
+
color: "theme-primary",
|
|
799
|
+
}}
|
|
800
|
+
>
|
|
801
|
+
Hover the card to change text color
|
|
802
|
+
</Element>
|
|
803
|
+
|
|
804
|
+
{/* Child background changes when parent is hovered */}
|
|
805
|
+
<Element
|
|
806
|
+
as="button"
|
|
807
|
+
backgroundColor="color-gray-100"
|
|
808
|
+
marginTop={12}
|
|
809
|
+
padding={8}
|
|
810
|
+
borderRadius={6}
|
|
811
|
+
transition="all 200ms"
|
|
812
|
+
|
|
813
|
+
_groupHover={{
|
|
814
|
+
backgroundColor: "theme-primary",
|
|
815
|
+
color: "color-white",
|
|
816
|
+
}}
|
|
817
|
+
>
|
|
818
|
+
Action Button
|
|
819
|
+
</Element>
|
|
820
|
+
</View>
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### Pseudo-Elements with Colors
|
|
826
|
+
|
|
827
|
+
You can also style pseudo-elements like `::before` and `::after` with colors:
|
|
828
|
+
|
|
829
|
+
```javascript
|
|
830
|
+
import { Element } from 'app-studio';
|
|
831
|
+
|
|
832
|
+
function PseudoElementButton() {
|
|
833
|
+
return (
|
|
834
|
+
<Element
|
|
835
|
+
as="button"
|
|
836
|
+
position="relative"
|
|
837
|
+
color="theme-primary"
|
|
838
|
+
fontWeight="bold"
|
|
839
|
+
paddingBottom={8}
|
|
840
|
+
|
|
841
|
+
// Create underline effect with ::after
|
|
842
|
+
_after={{
|
|
843
|
+
content: '""',
|
|
844
|
+
position: 'absolute',
|
|
845
|
+
bottom: 0,
|
|
846
|
+
left: 0,
|
|
847
|
+
right: 0,
|
|
848
|
+
height: 2,
|
|
849
|
+
backgroundColor: "theme-primary",
|
|
850
|
+
transform: 'scaleX(0)',
|
|
851
|
+
transition: 'transform 200ms',
|
|
852
|
+
transformOrigin: 'center',
|
|
853
|
+
}}
|
|
854
|
+
|
|
855
|
+
// Expand underline on hover
|
|
856
|
+
_hover={{
|
|
857
|
+
_after: {
|
|
858
|
+
transform: 'scaleX(1)',
|
|
859
|
+
},
|
|
860
|
+
}}
|
|
861
|
+
>
|
|
862
|
+
Underline Effect
|
|
863
|
+
</Element>
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
```
|
|
867
|
+
|
|
638
868
|
## Using Colors with Animations
|
|
639
869
|
|
|
640
870
|
When using colors in CSS animations or gradients, you can reference theme variables directly using the `var(--color-*)` syntax. This is especially useful for scroll-driven animations like `fillTextScroll()`.
|
|
@@ -724,3 +954,234 @@ All color palettes have CSS variables available:
|
|
|
724
954
|
| `gray` | `var(--color-gray-800)` | Text on light backgrounds |
|
|
725
955
|
|
|
726
956
|
See [docs/Animation.md](./Animation.md) for complete animation examples with theming.
|
|
957
|
+
|
|
958
|
+
## Responsive Colors with Media Queries
|
|
959
|
+
|
|
960
|
+
Use the `media` prop to define different colors for different screen sizes:
|
|
961
|
+
|
|
962
|
+
```javascript
|
|
963
|
+
import { View, Text } from 'app-studio';
|
|
964
|
+
|
|
965
|
+
function ResponsiveCard() {
|
|
966
|
+
return (
|
|
967
|
+
<View
|
|
968
|
+
backgroundColor="theme-primary"
|
|
969
|
+
padding={16}
|
|
970
|
+
|
|
971
|
+
// Responsive backgrounds based on screen size
|
|
972
|
+
media={{
|
|
973
|
+
mobile: {
|
|
974
|
+
backgroundColor: "color-blue-500",
|
|
975
|
+
padding: 8,
|
|
976
|
+
},
|
|
977
|
+
tablet: {
|
|
978
|
+
backgroundColor: "color-blue-600",
|
|
979
|
+
padding: 12,
|
|
980
|
+
},
|
|
981
|
+
desktop: {
|
|
982
|
+
backgroundColor: "color-blue-700",
|
|
983
|
+
padding: 20,
|
|
984
|
+
},
|
|
985
|
+
}}
|
|
986
|
+
>
|
|
987
|
+
<Text color="color-white">Responsive colors</Text>
|
|
988
|
+
</View>
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
## Color Accessibility Guidelines
|
|
994
|
+
|
|
995
|
+
### Text Contrast
|
|
996
|
+
|
|
997
|
+
Always ensure sufficient contrast between text and background colors:
|
|
998
|
+
|
|
999
|
+
```javascript
|
|
1000
|
+
// Good: High contrast
|
|
1001
|
+
<View backgroundColor="color-white">
|
|
1002
|
+
<Text color="color-gray-900">Good contrast</Text>
|
|
1003
|
+
</View>
|
|
1004
|
+
|
|
1005
|
+
// Poor: Low contrast - avoid
|
|
1006
|
+
<View backgroundColor="color-gray-100">
|
|
1007
|
+
<Text color="color-gray-200">Poor contrast</Text>
|
|
1008
|
+
</View>
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
### Using Semantic Colors
|
|
1012
|
+
|
|
1013
|
+
Use theme colors semantically for consistency:
|
|
1014
|
+
|
|
1015
|
+
```javascript
|
|
1016
|
+
const theme = {
|
|
1017
|
+
colors: {
|
|
1018
|
+
success: "color-emerald-500", // For positive actions
|
|
1019
|
+
error: "color-red-500", // For errors/warnings
|
|
1020
|
+
warning: "color-amber-500", // For warnings
|
|
1021
|
+
info: "color-blue-500", // For information
|
|
1022
|
+
disabled: "color-gray-400", // For disabled states
|
|
1023
|
+
},
|
|
1024
|
+
};
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
### Color Opacity for Subtle Effects
|
|
1028
|
+
|
|
1029
|
+
Use alpha transparency for less intrusive elements:
|
|
1030
|
+
|
|
1031
|
+
```javascript
|
|
1032
|
+
import { View, Text } from 'app-studio';
|
|
1033
|
+
|
|
1034
|
+
function SuccessMessage() {
|
|
1035
|
+
return (
|
|
1036
|
+
<View
|
|
1037
|
+
backgroundColor="color-emerald-500-100" // 10% opacity
|
|
1038
|
+
borderColor="color-emerald-500"
|
|
1039
|
+
borderWidth={1}
|
|
1040
|
+
borderRadius={8}
|
|
1041
|
+
padding={12}
|
|
1042
|
+
>
|
|
1043
|
+
<Text color="color-emerald-900">Success!</Text>
|
|
1044
|
+
</View>
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
## Advanced Color Patterns
|
|
1050
|
+
|
|
1051
|
+
### Dynamic Theme Switching
|
|
1052
|
+
|
|
1053
|
+
```javascript
|
|
1054
|
+
import { ThemeProvider, View, Button, Text } from 'app-studio';
|
|
1055
|
+
import { useState } from 'react';
|
|
1056
|
+
|
|
1057
|
+
function AppWithThemeToggle() {
|
|
1058
|
+
const [mode, setMode] = useState('light');
|
|
1059
|
+
|
|
1060
|
+
const theme = {
|
|
1061
|
+
primary: mode === 'light' ? 'color-blue-600' : 'color-blue-400',
|
|
1062
|
+
background: mode === 'light' ? 'color-white' : 'color-gray-900',
|
|
1063
|
+
text: mode === 'light' ? 'color-gray-900' : 'color-white',
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
return (
|
|
1067
|
+
<ThemeProvider theme={theme} mode={mode}>
|
|
1068
|
+
<View
|
|
1069
|
+
backgroundColor="theme-background"
|
|
1070
|
+
color="theme-text"
|
|
1071
|
+
padding={20}
|
|
1072
|
+
minHeight="100vh"
|
|
1073
|
+
>
|
|
1074
|
+
<Button
|
|
1075
|
+
onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}
|
|
1076
|
+
backgroundColor="theme-primary"
|
|
1077
|
+
>
|
|
1078
|
+
Toggle {mode === 'light' ? 'Dark' : 'Light'} Mode
|
|
1079
|
+
</Button>
|
|
1080
|
+
</View>
|
|
1081
|
+
</ThemeProvider>
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
### Gradient Colors with Transparency
|
|
1087
|
+
|
|
1088
|
+
```javascript
|
|
1089
|
+
import { View } from 'app-studio';
|
|
1090
|
+
|
|
1091
|
+
function GradientCard() {
|
|
1092
|
+
return (
|
|
1093
|
+
<View
|
|
1094
|
+
background={`
|
|
1095
|
+
linear-gradient(
|
|
1096
|
+
135deg,
|
|
1097
|
+
color-mix(in srgb, var(--color-blue-500) 100%, transparent) 0%,
|
|
1098
|
+
color-mix(in srgb, var(--color-purple-500) 100%, transparent) 100%
|
|
1099
|
+
)
|
|
1100
|
+
`}
|
|
1101
|
+
padding={24}
|
|
1102
|
+
borderRadius={12}
|
|
1103
|
+
>
|
|
1104
|
+
{/* content */}
|
|
1105
|
+
</View>
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
### Stacked State Modifiers
|
|
1111
|
+
|
|
1112
|
+
You can nest state modifiers for complex interactions:
|
|
1113
|
+
|
|
1114
|
+
```javascript
|
|
1115
|
+
import { Element } from 'app-studio';
|
|
1116
|
+
|
|
1117
|
+
function ComplexButton() {
|
|
1118
|
+
return (
|
|
1119
|
+
<Element
|
|
1120
|
+
as="button"
|
|
1121
|
+
backgroundColor="theme-primary"
|
|
1122
|
+
color="color-white"
|
|
1123
|
+
|
|
1124
|
+
_hover={{
|
|
1125
|
+
backgroundColor: "theme-primary-600",
|
|
1126
|
+
|
|
1127
|
+
// Nested focus state
|
|
1128
|
+
_focus: {
|
|
1129
|
+
outline: "2px solid",
|
|
1130
|
+
outlineColor: "color-white",
|
|
1131
|
+
},
|
|
1132
|
+
}}
|
|
1133
|
+
|
|
1134
|
+
_active={{
|
|
1135
|
+
backgroundColor: "theme-primary-700",
|
|
1136
|
+
transform: "scale(0.98)",
|
|
1137
|
+
}}
|
|
1138
|
+
|
|
1139
|
+
_disabled={{
|
|
1140
|
+
backgroundColor: "color-gray-400",
|
|
1141
|
+
opacity: 0.5,
|
|
1142
|
+
}}
|
|
1143
|
+
>
|
|
1144
|
+
Complex State
|
|
1145
|
+
</Element>
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
## Color Debugging Tips
|
|
1151
|
+
|
|
1152
|
+
### Using CSS Variables Directly
|
|
1153
|
+
|
|
1154
|
+
If you need to inspect theme colors:
|
|
1155
|
+
|
|
1156
|
+
```javascript
|
|
1157
|
+
// In browser console:
|
|
1158
|
+
// getComputedStyle(document.documentElement)
|
|
1159
|
+
// .getPropertyValue('--color-blue-500')
|
|
1160
|
+
// or
|
|
1161
|
+
// getComputedStyle(document.documentElement)
|
|
1162
|
+
// .getPropertyValue('--theme-primary')
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
### Checking Color Availability
|
|
1166
|
+
|
|
1167
|
+
See what colors are available in your theme:
|
|
1168
|
+
|
|
1169
|
+
```javascript
|
|
1170
|
+
import { useTheme } from 'app-studio';
|
|
1171
|
+
|
|
1172
|
+
function ColorDebugger() {
|
|
1173
|
+
const { colors } = useTheme();
|
|
1174
|
+
|
|
1175
|
+
return (
|
|
1176
|
+
<pre>{JSON.stringify(colors, null, 2)}</pre>
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
## Color Performance Tips
|
|
1182
|
+
|
|
1183
|
+
1. **Use CSS Variables** - Reference theme colors via CSS variables for optimal performance
|
|
1184
|
+
2. **Limit Color Computations** - Pre-define commonly used color combinations
|
|
1185
|
+
3. **Leverage Inheritance** - Set colors on parent elements and inherit to children
|
|
1186
|
+
4. **Cache Color Mix Operations** - The browser caches `color-mix()` results
|
|
1187
|
+
5. **Avoid Inline Computations** - Use theme colors directly instead of computing colors in JavaScript
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.7.
|
|
2
|
+
"version": "0.7.12",
|
|
3
3
|
"name": "app-studio",
|
|
4
4
|
"description": "App Studio is a responsive and themeable framework to build cross platform applications",
|
|
5
5
|
"repository": "git@github.com:rize-network/app-studio.git",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"module": "dist/app-studio.esm.js",
|
|
10
10
|
"unpkg": "dist/app-studio.umd.production.min.js",
|
|
11
11
|
"typings": "dist/index.d.ts",
|
|
12
|
+
"sideEffects": false,
|
|
12
13
|
"keywords": [
|
|
13
14
|
"react",
|
|
14
15
|
"typescript",
|