so://phie

figure

The vanilla alternative for writing JSX-based React applications
git clone git://soophie.de/figure

blob: 950e26a65624de5e3b9dfc30970a5d60275d6d43 (2846 bytes)[doc][blame][raw]

1<div id="app"></div>

2

3<script type="module">

4

5 import {useState, createElement} from 'https://cdn.skypack.dev/react';

6 import {render} from 'https://cdn.skypack.dev/react-dom';

7 import {createTlx} from './lib.js';

8

9 const tlx = createTlx(createElement);

10

11 const Button = (props, $slot) => {

12 const styles = {

13 minWidth: '40px',

14 height: '40px',

15 border: 'none',

16 outline: 'none',

17 border: '1px solid #a3a3a3',

18 backgroundColor: props.disabled ? '#f5f5f5' : '#e5e5e5',

19 cursor: props.disabled ? 'default' : 'pointer',

20 fontSize: '1rem',

21 fontFamily: 'Inter',

22 ...props.styles

23 };

24 return tlx`

25 <button disabled="${props.disabled}" style="${styles}" @click="${() => props.onClick()}">${$slot}</button>

26 `;

27 }

28

29 const Counter = (props) => {

30 const [defaultValue, setDefaultValue] = useState(0);

31 const { min = 0, max = 999, value = defaultValue, setValue = setDefaultValue } = props ?? {};

32 const validate = (value) => {

33 if(/^\d+$/.test(value) && parseInt(value) <= max) {

34 setValue(parseInt(value));

35 }

36 }

37 return tlx`

38 <div style="display: inline-flex; width: 100%; border: 1px solid #a3a3a3; border-radius: 4px; overflow: hidden; height: 40px; box-sizing: border-box;">

39 ${Button({

40 onClick: () => setValue(value - 1),

41 styles: {

42 fontSize: '1.2rem',

43 borderWidth: '0px 1px 0px 0px'

44 },

45 disabled: value <= min

46 }, '-')}

47 <input type="text" @input="${(event) => validate(event.target.value)}" value="${value}" style="font-size: 1rem; text-align: center; border: none; flex: 1; min-width: 0; height: 40px; outline: none;">

48 ${Button({

49 onClick: () => setValue(value + 1),

50 styles: {

51 fontSize: '1.2rem',

52 borderWidth: '0px 0px 0px 1px'

53 },

54 disabled: value >= max

55 }, '+')}

56 </div>

57 `;

58 }

59

60 const App = () => {

61 const [quantity, setQuantity] = useState(1);

62 const isDisabled = quantity <= 0;

63 return tlx`

64 <div style="margin: 100px; display: flex; width: 150px; flex-direction: column; gap: 15px; align-items: flex-start;">

65 ${Counter({ value: quantity, setValue: setQuantity })}

66 ${Button({

67 styles: {

68 backgroundColor: isDisabled ? '#f5f5f5' : '#f97316',

69 borderColor: isDisabled ? '#d4d4d4' : '#c2410c',

70 color: isDisabled ? '#a3a3a3' : 'white',

71 borderRadius: '4px',

72 width: '100%'

73 },

74 onClick: () => alert(`Added ${quantity} ${quantity > 1 ? 'items' : 'item'} to the cart`),

75 disabled: isDisabled

76 }, 'Add to cart')}

77 </div>

78 `;

79 }

80

81 const app = document.querySelector('#app');

82 render(createElement(App), app);

83

84</script>