nitro-web 0.0.192 → 0.0.193

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.
@@ -1,38 +1,68 @@
1
1
  import { twMerge } from 'nitro-web/util'
2
2
 
3
+ type NamedSize = 'big' | 'medium' | 'normal' | 'small'
4
+ type Size = NamedSize | number
5
+
3
6
  type InitialsProps = {
4
- icon?: { initials: string, hex?: string }
5
- isBig?: boolean
6
- isMedium?: boolean
7
- isSmall?: boolean
7
+ initials: string,
8
+ color?: string, // e.g. '#067306' or 'text-primary'
9
+ colorBg?: string, // e.g. '#06730618' or 'bg-primary' (if not passed, color will be used)
10
+ opacityBg?: number, // e.g. 0.18
11
+ colors?: string[], // e.g. ['#067306']
12
+ size?: Size, // named ('big', 'medium', 'small') or pixel number (e.g. 20)
8
13
  isRound?: boolean
9
14
  className?: string
10
15
  }
11
16
 
12
- export function Initials({ icon, isBig, isMedium, isSmall, isRound, className }: InitialsProps) {
13
- const color = icon?.hex || icon?.initials && getColorByLetter(icon?.initials) || '#000000'
17
+ // Returns tailwind classes for the nearest named size bucket
18
+ function sizeClasses(size: Size): string {
19
+ const px = typeof size === 'number' ? size : { big: 30, medium: 26, normal: 24, small: 21 }[size]
20
+ if (px <= 21) return 'size-[21px] text-[10px]'
21
+ else if (px <= 24) return 'size-[24px] text-[11px]' // default
22
+ else if (px <= 26) return 'size-[26px] text-[12px]'
23
+ else return 'size-[30px] text-[13px]'
24
+ }
25
+
26
+ export function Initials({ initials, color, colorBg, colors, opacityBg, size, isRound, className }: InitialsProps) {
27
+ // Check if className colors were passed
28
+ const colorFgClass = color?.startsWith('text-') ? color : undefined
29
+ const colorBgClass = colorBg?.startsWith('bg-') ? colorBg : undefined
30
+ if ((colorFgClass || colorBgClass) && (!color || !colorBg)) {
31
+ throw new Error('When using className colors, `color` and `colorBg` params are required')
32
+ }
33
+ // Check if hex colors were passed, otherwise use the color by letter
34
+ const colorFgHex = colorFgClass ? undefined : (color || getColorByLetter(initials, colors))
35
+ const colorBgHex = colorBgClass ? undefined : (colorBg || colorFgHex)
36
+
37
+ const sizeStyle = typeof size === 'number' ? { width: `${size}px`, height: `${size}px` } : {}
38
+
14
39
  return (
15
- <span
40
+ <span
41
+ style={{ color: colorFgHex, ...sizeStyle }}
16
42
  className={twMerge(
17
- 'nitro-initials flex items-center justify-center rounded-[5px] font-bold text-[11px] size-[24px]',
18
- isBig && 'size-[40px] text-sm',
19
- isMedium && 'size-[30px] text-xs',
20
- isSmall && 'size-[22px]',
43
+ (
44
+ 'nitro-initials flex-shrink-0 inline-flex items-center justify-center font-bold text-[11px] size-[24px] relative rounded-md ' +
45
+ `overflow-hidden ring-1 ring-inset ring-[#00000012] ${colorFgClass}`
46
+ ),
47
+ sizeClasses(size || 'normal'),
21
48
  isRound && 'rounded-full',
22
- !icon && 'w-0',
49
+ !initials && 'w-0',
23
50
  className
24
51
  )}
25
- style={icon ? {backgroundColor: color + '18', color: color} : {}}
26
52
  >
27
- {icon?.initials}
53
+ <span
54
+ style={colorBgHex ? { backgroundColor: colorBgHex } : {}}
55
+ className={`absolute inset-0 ${opacityBg || 'opacity-[10%]'} ${colorBgClass}`}
56
+ />
57
+ {initials}
28
58
  </span>
29
59
  )
30
60
  }
31
61
 
32
- export function getColorByLetter(letter: string) {
33
- const colors = ['#067306', '#AA33FF', '#FF54AF', '#F44336', '#c03c3c', '#5451e0', '#d88c1b']
62
+ export function getColorByLetter(letter: string, colors?: string[]) {
63
+ const colors2 = colors || ['#067306', '#AA33FF', '#FF54AF', '#F44336', '#c03c3c', '#5451e0', '#d88c1b']
34
64
  const charIndex = letter.toLowerCase().charCodeAt(0) - 97
35
65
  const charIndexLimited = (charIndex < 0 || charIndex > 25) ? 25 : charIndex
36
- const index = Math.round(charIndexLimited / 25 * (colors.length-1))
37
- return colors[index]
66
+ const index = Math.round(charIndexLimited / 25 * (colors2.length-1))
67
+ return colors2[index]
38
68
  }
@@ -26,6 +26,8 @@ type GetSelectClassName = {
26
26
  export type SelectOption = {
27
27
  value: unknown,
28
28
  label: string | React.ReactNode,
29
+ labelSearch?: string,
30
+ noTruncate?: boolean,
29
31
  fixed?: boolean,
30
32
  IconLeft?: React.ReactNode,
31
33
  flag?: string | React.ReactNode,
@@ -131,7 +133,8 @@ function SelectBase({
131
133
  id={containerId}
132
134
  filterOption={(option, searchText) => {
133
135
  if ((option.data as {fixed?: boolean}).fixed) return true
134
- return filterFn(option, searchText)
136
+ const labelSearch = (option.data as {labelSearch?: string}).labelSearch
137
+ return filterFn(labelSearch ? { ...option, label: labelSearch } : option, searchText)
135
138
  }}
136
139
  menuPlacement="auto"
137
140
  minMenuHeight={250}
@@ -206,7 +209,7 @@ function ValueContainer({ children, ...props}: ValueContainerProps) {
206
209
  }
207
210
 
208
211
  function SingleValue({ children, ...props }: SingleValueProps) {
209
- const selectedOption = props.getValue()[0] as { labelControl?: string, flag?: string | React.ReactNode, IconLeft?: React.ReactNode }
212
+ const selectedOption = props.getValue()[0] as { labelControl?: string } & SelectOption
210
213
  // @ts-expect-error
211
214
  const flagClassName = props.getClassNames('flag')
212
215
 
@@ -218,7 +221,10 @@ function SingleValue({ children, ...props }: SingleValueProps) {
218
221
  : <Fragment>
219
222
  {selectedOption?.flag && <span className={flagClassName}>{selectedOption.flag}</span>}
220
223
  {selectedOption?.IconLeft}
221
- <span class="overflow-hidden text-ellipsis whitespace-nowrap">{children}</span>
224
+ {selectedOption?.noTruncate
225
+ ? children
226
+ : <span class="overflow-hidden text-ellipsis whitespace-nowrap">{children}</span>
227
+ }
222
228
  </Fragment>
223
229
  }
224
230
  </components.SingleValue>
@@ -226,14 +232,14 @@ function SingleValue({ children, ...props }: SingleValueProps) {
226
232
  }
227
233
 
228
234
  function Option(props: OptionProps) {
229
- const data = props.data as { className?: string, flag?: string | React.ReactNode, IconLeft?: React.ReactNode }
235
+ const data = props.data as { className?: string } & SelectOption
230
236
  // const _nitro = (props.selectProps as { _nitro?: { mode?: string } })?._nitro
231
237
  // @ts-expect-error
232
238
  const flagClassName = props.getClassNames('flag')
233
239
  return (
234
240
  <components.Option className={data.className} {...props}>
235
241
  <span class="flex-auto min-w-0">{data.flag && <span className={flagClassName}>{data.flag}</span>}{data.IconLeft}{props.label}</span>
236
- {props.isSelected && <CheckCircleIcon className="size-[22px] text-primary -my-1 -mx-0.5" />}
242
+ {props.isSelected && <CheckCircleIcon className="flex-shrink-0 size-[22px] text-primary -my-1 -mx-0.5" />}
237
243
  </components.Option>
238
244
  )
239
245
  }
@@ -9,6 +9,23 @@ import { Check, EllipsisVerticalIcon, FileEditIcon } from 'lucide-react'
9
9
  import React from 'react'
10
10
 
11
11
  const perPage = 10
12
+ const allGroups = [
13
+ 'Links',
14
+ 'Dropdowns',
15
+ 'Filters',
16
+ 'Button Colors & Sizes',
17
+ 'Button Icons',
18
+ 'Loading Elements',
19
+ 'Varients',
20
+ 'Selects',
21
+ 'Inputs',
22
+ 'Date Inputs',
23
+ 'File Inputs & Calendar & Time',
24
+ 'Tables',
25
+ 'Modals & Notifications',
26
+ 'Custom Components',
27
+ ] as const
28
+
12
29
  const statusColors = function(status: string) {
13
30
  return {
14
31
  pending: 'bg-yellow-400',
@@ -22,6 +39,7 @@ type StyleguideProps = {
22
39
  elements?: { Button?: typeof ButtonNitro }
23
40
  children?: React.ReactNode
24
41
  currencies?: { [key: string]: { name: string, symbol: string, digits: number } }
42
+ groups?: Array<typeof allGroups[number]>
25
43
  }
26
44
 
27
45
  type QuoteExample = {
@@ -33,29 +51,14 @@ type QuoteExample = {
33
51
  status: string
34
52
  }
35
53
 
36
- export function Styleguide({ className, elements, children, currencies }: StyleguideProps) {
54
+ export function Styleguide({ className, elements, children, currencies, groups }: StyleguideProps) {
37
55
  const Button = elements?.Button || ButtonNitro
38
56
  const [, setStore] = useTracked()
39
57
  const [customerSearch, setCustomerSearch] = useState('')
40
58
  const [showModal1, setShowModal1] = useState(false)
41
59
 
42
60
  // Tip: handy when developing or updating components, you can hide/show the groups you want to see
43
- const groups = [
44
- 'Links',
45
- 'Dropdowns',
46
- 'Filters',
47
- 'Button Colors & Sizes',
48
- 'Button Icons',
49
- 'Loading Elements',
50
- 'Varients',
51
- 'Selects',
52
- 'Inputs',
53
- 'Date Inputs',
54
- 'File Inputs & Calendar & Time',
55
- 'Tables',
56
- 'Modals & Notifications',
57
- 'Custom Components',
58
- ]
61
+ const visibleGroups = groups || allGroups
59
62
  const [state, setState] = useState(() => getState())
60
63
 
61
64
  function getState(useOldValues?: boolean) {
@@ -252,7 +255,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
252
255
  </p>
253
256
  </div>
254
257
 
255
- {groups.includes('Links') && (
258
+ {visibleGroups.includes('Links') && (
256
259
  <div>
257
260
  <h2 class="h3">Links</h2>
258
261
  <div class="mb-6">
@@ -263,7 +266,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
263
266
  </div>
264
267
  )}
265
268
 
266
- {groups.includes('Dropdowns') && (
269
+ {visibleGroups.includes('Dropdowns') && (
267
270
  <div>
268
271
  <h2 class="h3">Dropdowns</h2>
269
272
  <div class="flex flex-wrap gap-x-6 gap-y-4 mb-6">
@@ -297,7 +300,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
297
300
  </div>
298
301
  )}
299
302
 
300
- {groups.includes('Filters') && (
303
+ {visibleGroups.includes('Filters') && (
301
304
  <div>
302
305
  <h2 class="h3">Filters</h2>
303
306
  <div class="flex flex-wrap gap-x-6 gap-y-4 mb-6">
@@ -327,7 +330,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
327
330
  </div>
328
331
  )}
329
332
 
330
- {groups.includes('Button Colors & Sizes') && (
333
+ {visibleGroups.includes('Button Colors & Sizes') && (
331
334
  <div>
332
335
  <h2 class="h3">Button Colors & Sizes</h2>
333
336
  <div class="flex flex-wrap gap-x-6 gap-y-4 mb-6">
@@ -351,7 +354,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
351
354
  </div>
352
355
  )}
353
356
 
354
- {groups.includes('Button Icons') && (
357
+ {visibleGroups.includes('Button Icons') && (
355
358
  <div>
356
359
  <h2 class="h3">Button Icons</h2>
357
360
  <div class="flex flex-wrap gap-x-6 gap-y-4 mb-6">
@@ -371,7 +374,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
371
374
  </div>
372
375
  )}
373
376
 
374
- {groups.includes('Loading Elements') && (
377
+ {visibleGroups.includes('Loading Elements') && (
375
378
  <div>
376
379
  <h2 class="h3">Loading Elements</h2>
377
380
  <div class="flex flex-wrap gap-x-6 gap-y-4 items-center mb-6">
@@ -383,7 +386,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
383
386
  </div>
384
387
  )}
385
388
 
386
- {groups.includes('Varients') && (
389
+ {visibleGroups.includes('Varients') && (
387
390
  <div>
388
391
  <h2 class="h3">Varients</h2>
389
392
  <div class="grid grid-cols-3 gap-x-6">
@@ -409,7 +412,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
409
412
  </div>
410
413
  )}
411
414
 
412
- {groups.includes('Selects') && (
415
+ {visibleGroups.includes('Selects') && (
413
416
  <div>
414
417
  <h2 class="h3">Selects</h2>
415
418
  <div class="grid grid-cols-3 lg:grid-cols-3 gap-x-6">
@@ -484,17 +487,17 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
484
487
  {
485
488
  value: '1',
486
489
  label: 'Wayne Enterprises',
487
- IconLeft: <Initials icon={{ initials: 'WE' }} className="inline-flex my-[-3px] mr-2 flex-shrink-0" />,
490
+ IconLeft: <Initials initials="WE" className="inline-flex my-[-3px] mr-2 flex-shrink-0" />,
488
491
  },
489
492
  {
490
493
  value: '2',
491
494
  label: 'Iceberg Lounge Limited',
492
- IconLeft: <Initials icon={{ initials: 'IL' }} className="inline-flex my-[-3px] mr-2 flex-shrink-0" />,
495
+ IconLeft: <Initials initials="IL" className="inline-flex my-[-3px] mr-2 flex-shrink-0" />,
493
496
  },
494
497
  {
495
498
  value: '3',
496
499
  label: 'Ace Chemicals Company',
497
- IconLeft: <Initials icon={{ initials: 'AC' }} className="inline-flex my-[-3px] mr-2 flex-shrink-0" />,
500
+ IconLeft: <Initials initials="AC" className="inline-flex my-[-3px] mr-2 flex-shrink-0" />,
498
501
  },
499
502
  ], [customerSearch])}
500
503
  />
@@ -526,7 +529,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
526
529
  </div>
527
530
  )}
528
531
 
529
- {groups.includes('Inputs') && (
532
+ {visibleGroups.includes('Inputs') && (
530
533
  <div>
531
534
  <h2 class="h3">Inputs</h2>
532
535
  <div class="grid grid-cols-3 gap-x-6">
@@ -587,7 +590,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
587
590
  </div>
588
591
  )}
589
592
 
590
- {groups.includes('Date Inputs') && (
593
+ {visibleGroups.includes('Date Inputs') && (
591
594
  <div>
592
595
  <h2 class="h3">Date Inputs</h2>
593
596
  <div class="grid grid-cols-1 gap-x-6 sm:grid-cols-3">
@@ -638,7 +641,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
638
641
  </div>
639
642
  )}
640
643
 
641
- {groups.includes('File Inputs & Calendar & Time') && (
644
+ {visibleGroups.includes('File Inputs & Calendar & Time') && (
642
645
  <div>
643
646
  <h2 class="h3">File Inputs & Calendar & Time</h2>
644
647
  <div class="grid grid-cols-3 gap-x-6">
@@ -675,7 +678,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
675
678
  </div>
676
679
  )}
677
680
 
678
- {groups.includes('Tables') && (
681
+ {visibleGroups.includes('Tables') && (
679
682
  <div>
680
683
  <div class="flex justify-between items-start">
681
684
  <h2 class="h3">Tables</h2>
@@ -738,7 +741,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
738
741
  </div>
739
742
  )}
740
743
 
741
- {groups.includes('Modals & Notifications') && (
744
+ {visibleGroups.includes('Modals & Notifications') && (
742
745
  <React.Fragment>
743
746
  <div>
744
747
  <h2 class="h3">Modals & Notifications</h2>
@@ -782,7 +785,7 @@ export function Styleguide({ className, elements, children, currencies }: Styleg
782
785
  </React.Fragment>
783
786
  )}
784
787
 
785
- {groups.includes('Custom Components') && (
788
+ {visibleGroups.includes('Custom Components') && (
786
789
  <React.Fragment>
787
790
  {children}
788
791
  </React.Fragment>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.192",
3
+ "version": "0.0.193",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",