5htp-core 0.4.9-97 → 0.4.9-98

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.4.9-97",
4
+ "version": "0.4.9-98",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -11,8 +11,8 @@
11
11
 
12
12
  // Layout
13
13
  position: relative;
14
- gap: @spacing;
15
- min-width: 0/*fit-content*/; // Fit content, even when flexbox parent width < content width
14
+ gap: @spacing / 2;
15
+ min-width: @sizeComponent; // Wdth should be < height
16
16
 
17
17
  // Dimensions
18
18
  font-size: 1em;
@@ -29,8 +29,7 @@
29
29
 
30
30
  // Colors
31
31
  // NOTE: transparent by default (menu items, etc..)
32
- background: transparent;
33
- color: var(--cTxtAccent);
32
+ background: var(--cBg);
34
33
 
35
34
  // Hover
36
35
  //transition: all .5s linear;
@@ -38,6 +37,7 @@
38
37
  li:hover > & {
39
38
 
40
39
  color: var(--cTxtImportant);
40
+ background: var(--cBgActive);
41
41
  //transition: all .1s linear;
42
42
 
43
43
  > i {
@@ -77,9 +77,14 @@
77
77
  }
78
78
  }
79
79
 
80
+ &.selected {
81
+ background: var(--cBgSelected);
82
+ color: #fff;
83
+ }
84
+
80
85
  // Click
81
86
  &.pressed {
82
- transform: scale(0.9);
87
+ background: var(--cBgPressed) !important;
83
88
  }
84
89
 
85
90
  &,
@@ -149,6 +154,11 @@
149
154
 
150
155
  }
151
156
 
157
+ &:not(.bg) {
158
+
159
+ color: var(--cTxtAccent);
160
+ }
161
+
152
162
  /*----------------------------------
153
163
  - STATE
154
164
  ----------------------------------*/
@@ -231,7 +241,7 @@
231
241
  // Give less imortance to buttons which are in lists
232
242
  color: var(--cTxtBase);
233
243
  box-shadow: none;
234
- //width: 100%;
244
+ padding: 0 1em; // Row display = more condensed
235
245
 
236
246
  &.active,
237
247
  &:hover {
@@ -239,14 +249,6 @@
239
249
  color: var(--cTxtImportant);
240
250
  }
241
251
 
242
- > .label {
243
- // All the list items label must be aligned
244
- justify-content: flex-start;
245
- // Since they're all horizontally aligned,
246
- // Label = max width, so icon right are also aligned to right
247
- flex: 1;
248
- }
249
-
250
252
  &.icon {
251
253
 
252
254
  color: var(--cTxtDesc);
@@ -273,6 +275,20 @@
273
275
  }
274
276
  }
275
277
 
278
+ .col {
279
+ &.menu > .btn,
280
+ &.menu > li > .btn {
281
+
282
+ > .label {
283
+ // All the list items label must be aligned
284
+ justify-content: flex-start;
285
+ // Since they're all horizontally aligned,
286
+ // Label = max width, so icon right are also aligned to right
287
+ flex: 1;
288
+ }
289
+ }
290
+ }
291
+
276
292
  ul.col,
277
293
  ul.row {
278
294
 
@@ -19,9 +19,7 @@
19
19
  // Default theming for the children components
20
20
  @{componentsSelector} {
21
21
  // Don't apply the default theme to already themed components
22
- &:not(.bg) {
23
- .apply-theme-style( @componentsTheme, false, false );
24
- }
22
+ .apply-theme-style( @componentsTheme, false, false );
25
23
  }
26
24
  }
27
25
  }
@@ -35,15 +33,23 @@
35
33
  @bgActive: if( (@theme[alpha]) or (alpha(@bg) < 1),
36
34
  fadeout( @bg, 90%),
37
35
  if( @isLight,
38
- @bg - #040404,
36
+ @bg - #0A0A0A,
39
37
  @bg + #111,
40
38
  )
41
39
  );
40
+ @bgPressed: if( (@theme[alpha]) or (alpha(@bg) < 1),
41
+ fadeout( @bg, 80%),
42
+ if( @isLight,
43
+ @bg - #1A1A1A,
44
+ @bg + #222,
45
+ )
46
+ );
42
47
  @fg: @theme[foreground];
43
48
 
44
49
  // Background
45
50
  --cBg: @bg;
46
51
  --cBgActive: @bgActive;
52
+ --cBgPressed: @bgPressed;
47
53
  & when (@apply = true) {
48
54
  background: var(--cBg);
49
55
  }
@@ -51,6 +57,7 @@
51
57
  // Accent
52
58
  & when (@theme[accent1]) {
53
59
  --cTxtAccent: @theme[accent1];
60
+ --cBgSelected: @@theme[accent1];
54
61
  }
55
62
  & when (@theme[accent2]) {
56
63
  --cTxtAccent2: @theme[accent2];
@@ -140,8 +140,11 @@
140
140
  }
141
141
  }
142
142
 
143
+ // Put this one at first because high possibilities we need to override
144
+ &.al-middle,
145
+ &.al-center { justify-content: center; }
146
+
143
147
  &, &.al-top { justify-content: flex-start; }
144
- &.al-middle, &.al-center { justify-content: center; }
145
148
  &.al-bottom { justify-content: flex-end; }
146
149
 
147
150
  &.al-left { align-items: flex-start; }
@@ -20,7 +20,7 @@ import type { Props } from '.';
20
20
  /*----------------------------------
21
21
  - COMPONENT
22
22
  ----------------------------------*/
23
- export default ({ choice, currentList, onChange, multiple, includeCurrent, format = 'badge' }: {
23
+ export default ({ choice, currentList, onChange, multiple, required, includeCurrent, format = 'badge' }: {
24
24
  choice: Choice,
25
25
  currentList: Choice[],
26
26
  includeCurrent?: boolean,
@@ -30,37 +30,36 @@ export default ({ choice, currentList, onChange, multiple, includeCurrent, forma
30
30
  const isCurrent = currentList.some(c => c.value === choice.value);
31
31
  if (isCurrent && !includeCurrent) return null;
32
32
 
33
- const showRemoveButton = multiple;
33
+ const canUnselect = !required || currentList.length > 1;
34
+
35
+ const onClick = () => {
36
+
37
+ if (isCurrent && !canUnselect)
38
+ return;
39
+
40
+ onChange( current => multiple
41
+ ? (isCurrent
42
+ ? currentList.filter(item => item.value !== choice.value)
43
+ : [...(current || []), choice]
44
+ )
45
+ : isCurrent ? undefined : choice
46
+ );
47
+ }
34
48
 
35
49
  return format === 'list' ? (
36
50
  <li>
37
- <Button active={isCurrent} onClick={() => onChange( current => multiple
38
- ? (isCurrent
39
- ? currentList.filter(item => item.value !== choice.value)
40
- : [...(current || []), choice]
41
- )
42
- : isCurrent ? undefined : choice
43
- )}>
51
+ <Button selected={isCurrent} onClick={onClick}>
44
52
  {choice.label}
45
53
  </Button>
46
54
  </li>
47
55
  ) : (
48
56
  <li>
49
- <Button type="secondary" active={isCurrent} onClick={() => onChange(current => multiple
50
- ? (isCurrent
51
- ? currentList.filter(item => item.value !== choice.value)
52
- : [...(current || []), choice]
53
- )
54
- : isCurrent ? undefined : choice
55
- )}>
57
+ <Button type="secondary" selected={isCurrent} onClick={onClick}>
58
+
56
59
  {choice.label}
57
60
 
58
- {showRemoveButton && (
59
- <span class="badge xs clickable" onClick={(e) => {
60
- e.stopPropagation();
61
- onChange( current => current.filter( c => c.value !== choice.value))
62
- return false;
63
- }}>
61
+ {(isCurrent && canUnselect) && (
62
+ <span class="badge xs clickable">
64
63
  x
65
64
  </span>
66
65
  )}
@@ -165,6 +165,7 @@ export default (props: Props) => {
165
165
  ----------------------------------*/
166
166
 
167
167
  const selectedItems = enableSearch ? currentList : []
168
+ const selectedItemsValue = selectedItems.map( c => c.value);
168
169
 
169
170
  const Search = enableSearch && (
170
171
  <Input
@@ -197,6 +198,7 @@ export default (props: Props) => {
197
198
  currentList={currentList}
198
199
  onChange={onChange}
199
200
  multiple={multiple}
201
+ required={required}
200
202
  includeCurrent
201
203
  />
202
204
  ))}
@@ -214,6 +216,7 @@ export default (props: Props) => {
214
216
  currentList={currentList}
215
217
  onChange={onChange}
216
218
  multiple={multiple}
219
+ required={required}
217
220
  includeCurrent
218
221
  />
219
222
  ))}
@@ -229,7 +232,7 @@ export default (props: Props) => {
229
232
  )}
230
233
  </div>
231
234
  )} state={popoverState}>
232
- <Button type="secondary" icon={icon} iconR="chevron-down" {...otherProps}>
235
+ <Button icon={icon} iconR="angle-down" {...otherProps}>
233
236
 
234
237
  {currentList.length === 0 ? <>
235
238
  {title}
@@ -239,51 +242,37 @@ export default (props: Props) => {
239
242
  {currentList[0].label}
240
243
  </>}
241
244
 
242
- {errors?.length && (
243
- <div class="bubble bg error bottom">
244
- {errors.join('. ')}
245
- </div>
246
- )}
247
-
248
245
  </Button>
249
246
  </Popover>
250
247
  ) : (
251
- <div class="col sp-05">
252
- <div class={className} onMouseDown={() => refInputSearch.current?.focus()}>
253
-
254
- <div class="row al-left wrap sp-05">
255
-
256
- {selectedItems.map( choice => (
257
- <ChoiceElement format='badge' choice={choice}
258
- currentList={currentList}
259
- onChange={onChange}
260
- multiple={multiple}
261
- includeCurrent
262
- />
263
- ))}
264
-
265
- {Search}
266
- </div>
267
-
268
- <ul class="row al-left wrap sp-05" style={{
269
- maxHeight: '30vh',
270
- }}>
271
- {choices.map( choice => (
272
- <ChoiceElement format='badge' choice={choice}
273
- currentList={currentList}
274
- onChange={onChange}
275
- multiple={multiple}
276
- includeCurrent
277
- />
278
- ))}
279
- </ul>
280
-
281
- </div>
282
- {errors?.length && (
283
- <div class="bubble bg error bottom">
284
- {errors.join('. ')}
285
- </div>
286
- )}
248
+ <div class={className} onMouseDown={() => refInputSearch.current?.focus()}>
249
+
250
+ {Search}
251
+
252
+ <ul class="row al-left wrap sp-05 scrollable mgt-1" style={{
253
+ maxHeight: '30vh',
254
+ }}>
255
+ {selectedItems.map( choice => (
256
+ <ChoiceElement format='badge' choice={choice}
257
+ currentList={currentList}
258
+ onChange={onChange}
259
+ multiple={multiple}
260
+ required={required}
261
+ includeCurrent
262
+ />
263
+ ))}
264
+
265
+ {choices.map( choice => !selectedItemsValue.includes(choice.value) && (
266
+ <ChoiceElement format='badge' choice={choice}
267
+ currentList={currentList}
268
+ onChange={onChange}
269
+ multiple={multiple}
270
+ required={required}
271
+ includeCurrent
272
+ />
273
+ ))}
274
+ </ul>
275
+
287
276
  </div>
288
277
  )}
289
278
  </InputWrapper>
@@ -35,6 +35,7 @@ export type Props = {
35
35
 
36
36
  state?: [string, React.StateUpdater<string>],
37
37
  active?: boolean,
38
+ selected?: boolean,
38
39
  disabled?: boolean,
39
40
  loading?: boolean,
40
41
  autoFocus?: boolean,
@@ -92,6 +93,7 @@ export default ({
92
93
 
93
94
  // Interactions
94
95
  active,
96
+ selected,
95
97
  state: stateUpdater,
96
98
  disabled,
97
99
  loading,
@@ -106,7 +108,8 @@ export default ({
106
108
  }: Props) => {
107
109
 
108
110
  const ctx = useContext();
109
- let [isActive, setIsSelected] = React.useState(false);
111
+ let [isSelected, setIsSelected] = React.useState(false);
112
+ let [isActive, setIsActive] = React.useState(false);
110
113
  const [isLoading, setLoading] = React.useState(false);
111
114
 
112
115
  if (isLoading || loading) {
@@ -118,29 +121,28 @@ export default ({
118
121
  if (stateUpdater && id !== undefined) {
119
122
  const [active, setActive] = stateUpdater;
120
123
  if (id === active)
121
- isActive = true;
124
+ isSelected = true;
122
125
  props.onClick = () => setActive(id);
123
126
  }
124
127
 
125
128
  // Shape classes
126
- className = className === undefined ? 'btn' : 'btn ' + className;
129
+ const classNames: string[] = ['btn'];
130
+ if (className)
131
+ classNames.push(className);
127
132
 
128
133
  if (shape !== undefined) {
129
134
  if (shape === 'tile')
130
- className += ' col';
135
+ classNames.push('col');
131
136
  else
132
- className += ' ' + shape;
137
+ classNames.push(shape);
133
138
  }
134
139
 
135
140
  if (size !== undefined)
136
- className += ' ' + size;
137
-
138
- if (type !== undefined)
139
- className += type === 'link' ? type : (' bg ' + type);
141
+ classNames.push(size);
140
142
 
141
143
  if (icon) {
142
144
  if (children === undefined)
143
- className += ' icon';
145
+ classNames.push('icon');
144
146
  }
145
147
 
146
148
  // state classes
@@ -148,11 +150,17 @@ export default ({
148
150
  props.onMouseDown = () => setMouseDown(true);
149
151
  props.onMouseUp = () => setMouseDown(false);
150
152
  props.onMouseLeave = () => setMouseDown(false);
151
- if (isMouseDown)
152
- className += ' pressed';
153
153
 
154
+ // Theming & state
155
+ if (isMouseDown)
156
+ classNames.push('pressed');
157
+ else if (selected || isSelected === true)
158
+ classNames.push('bg accent');
159
+ else if (type !== undefined)
160
+ classNames.push(type === 'link' ? type : (' bg ' + type));
161
+
154
162
  if (active || isActive === true)
155
- className += ' active';
163
+ classNames.push('active');
156
164
 
157
165
  // Icon
158
166
  if (prefix === undefined && icon !== undefined)
@@ -180,12 +188,12 @@ export default ({
180
188
 
181
189
  // Init
182
190
  if (checkIfCurrentUrl(ctx.request.path))
183
- setIsSelected(true);
191
+ setIsActive(true);
184
192
 
185
193
  // On location change
186
194
  return history?.listen(({ location }) => {
187
195
 
188
- setIsSelected( checkIfCurrentUrl(location.pathname) );
196
+ setIsActive( checkIfCurrentUrl(location.pathname) );
189
197
 
190
198
  })
191
199
 
@@ -207,7 +215,7 @@ export default ({
207
215
  }
208
216
 
209
217
  let render: VNode = (
210
- <Tag {...props} id={id} class={className} disabled={disabled} ref={refElem} onClick={(e: MouseEvent) => {
218
+ <Tag {...props} id={id} class={classNames.join(' ')} disabled={disabled} ref={refElem} onClick={(e: MouseEvent) => {
211
219
 
212
220
  // annulation si:
213
221
  // - Pas clic gauche
@@ -53,7 +53,7 @@ export default (props: Props) => {
53
53
  </div>
54
54
  )} state={popoverState} {...(popover || {})}>
55
55
 
56
- <Button {...buttonProps} iconR={<i src="chevron-down" class="s" />}
56
+ <Button {...buttonProps} iconR={<i src="angle-down" class="s" />}
57
57
  refElem={refButton} children={label} />
58
58
 
59
59
  </Popover>
@@ -87,10 +87,5 @@ export default ({
87
87
  />
88
88
  </div>
89
89
  </div>
90
- {errors?.length && (
91
- <div class="bubble bg error bottom">
92
- {errors.join('. ')}
93
- </div>
94
- )}
95
90
  </>
96
91
  }
@@ -75,11 +75,5 @@ export default ({
75
75
  )}
76
76
 
77
77
  </div>
78
-
79
- {errors?.length && (
80
- <div class="bubble bg error bottom">
81
- {errors.join('. ')}
82
- </div>
83
- )}
84
78
  </>
85
79
  }
@@ -135,12 +135,6 @@ export default (props: Props & InputBaseProps<string>) => {
135
135
  }
136
136
  }}
137
137
  /> */}
138
-
139
- {errors?.length && (
140
- <div class="bubble bg error bottom">
141
- {errors.join('. ')}
142
- </div>
143
- )}
144
138
  </div>
145
139
  </InputWrapper>
146
140
  )
@@ -735,7 +735,7 @@ function TableCellActionMenuContainer({
735
735
  setIsMenuOpen(!isMenuOpen);
736
736
  }}
737
737
  ref={menuRootRef}>
738
- <i className="chevron-down" />
738
+ <i className="angle-down" />
739
739
  </button>
740
740
 
741
741
  {isMenuOpen && (
@@ -244,7 +244,7 @@ export default function DropDown({
244
244
  {buttonLabel && (
245
245
  <span className="text dropdown-button-text">{buttonLabel}</span>
246
246
  )}
247
- <i className="chevron-down" />
247
+ <i className="angle-down" />
248
248
  </button>
249
249
 
250
250
  {showDropDown &&
@@ -27,33 +27,8 @@
27
27
  }
28
28
  }
29
29
 
30
- .input {
31
- &.text,
32
- &.select {
33
-
34
- background: var(--cBg);
35
- border-radius: @radius;
36
-
37
- > i {
38
- color: var(--cTxtDesc);
39
- }
40
- }
41
-
42
- // Error bubble
43
- position: relative;
44
- }
45
-
46
30
  .input.select {
47
-
48
- padding: 0;
49
-
50
- .input.text {
51
- border: none;
52
- box-shadow: none;
53
- padding: 0;
54
- height: auto;
55
- width: 150px;
56
- }
31
+
57
32
  }
58
33
 
59
34
  .input.text {
@@ -68,9 +43,23 @@
68
43
  // Since they are not supposed to be on the same row (mobile first design)
69
44
  height: @hInput;
70
45
  align-items: center;
46
+
47
+ background: var(--cBg);
48
+ border-radius: @radius;
49
+ transition: background .1s linear;
50
+
51
+ > i {
52
+ color: var(--cTxtDesc);
53
+ }
71
54
 
72
- --cBg2: #eee;
73
- //box-shadow: 1px 3px 0 fade(#000,4%), 0 1px 2px 0 fade(#000,2%);
55
+ &:hover {
56
+ background: var(--cBgActive);
57
+ }
58
+
59
+ &.focus {
60
+ background: #fff;
61
+ box-shadow: 1px 3px 0 fade(#000,4%), 0 1px 2px 0 fade(#000,2%);
62
+ }
74
63
 
75
64
  @gapAround: @spacing;
76
65
  > .btn:first-child { margin-left: 0 - @gapAround / 2; }
@@ -96,7 +96,7 @@ export function useInput<TValue>(
96
96
  /*----------------------------------
97
97
  - COMPONENT
98
98
  ----------------------------------*/
99
- export const InputWrapper = ({ children, wrapper = true, title, hint, required, className = '' }: InputBaseProps<unknown> & {
99
+ export const InputWrapper = ({ children, wrapper = true, title, hint, required, errors, className = '' }: InputBaseProps<unknown> & {
100
100
  children: ComponentChild
101
101
  }) => {
102
102
 
@@ -123,6 +123,12 @@ export const InputWrapper = ({ children, wrapper = true, title, hint, required,
123
123
  {hint && <p class="hint">{hint}</p>}
124
124
 
125
125
  {children}
126
+
127
+ {errors?.length && (
128
+ <div class="bubble bg error bottom">
129
+ {errors.join('. ')}
130
+ </div>
131
+ )}
126
132
 
127
133
  </div>
128
134
  )
@@ -200,12 +200,6 @@ export default (props: Props & InputBaseProps<string> & TInputElementProps) => {
200
200
  </div>
201
201
 
202
202
  {suffix}
203
-
204
- {errors?.length && (
205
- <div class="bubble bg error bottom">
206
- {errors.join('. ')}
207
- </div>
208
- )}
209
203
 
210
204
  </div>
211
205
  </InputWrapper>