Narrow component prop types, remove unused props and dead code (#2838)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Paweł Kuna
2026-08-09 23:14:33 +02:00
committed by GitHub
co-authored by StarDev
parent 0085eeba6e
commit 4f7beecd2b
90 changed files with 265 additions and 656 deletions
+1 -5
View File
@@ -4,11 +4,7 @@ import activity from '@data/activity.json'
import people from '@data/people.json'
import { timeagoLabel } from '@shared/lib/pseudo-random'
interface Props {
limit?: number
}
const { limit = 40 } = Astro.props
const limit = 40
interface Person {
full_name?: string
+8 -21
View File
@@ -1,34 +1,33 @@
---
import Icon from './Icon.astro'
import ButtonList from './ButtonList.astro'
/** alert-{type} / btn-{type} — matches defaultIcons below */
type AlertType = 'success' | 'warning' | 'danger' | 'info'
interface Props {
type?: string
icon?: string
type?: AlertType
important?: boolean
minor?: boolean
showClose?: boolean
avatar?: boolean
class?: string
title?: string
description?: string
list?: string[]
action?: string
link?: string
buttons?: boolean
}
const { type = 'success', icon: iconProp, important, minor, showClose, avatar, class: className, title = 'This is a custom alert box!', description, list, action, link, buttons } = Astro.props
const { type = 'success', important, minor, showClose, class: className, title = 'This is a custom alert box!', description, list, action, link } = Astro.props
const defaultIcons: Record<string, string> = {
const defaultIcons: Record<AlertType, string> = {
success: 'check',
warning: 'alert-triangle',
danger: 'alert-circle',
info: 'info-circle',
}
const icon = iconProp ?? defaultIcons[type]
const icon = defaultIcons[type]
const classes = ['alert', important ? 'alert-important' : minor ? 'alert-minor' : undefined, `alert-${type}`, showClose && 'alert-dismissible', avatar && 'alert-avatar', className]
const classes = ['alert', important ? 'alert-important' : minor ? 'alert-minor' : undefined, `alert-${type}`, showClose && 'alert-dismissible', className]
---
<div class:list={classes} role="alert">
@@ -65,17 +64,5 @@ const classes = ['alert', important ? 'alert-important' : minor ? 'alert-minor'
</Fragment>
)
}
{
buttons && (
<ButtonList>
<a href="#" class={`btn btn-${type}`}>
Okay
</a>
<a href="#" class="btn">
Cancel
</a>
</ButtonList>
)
}
{showClose && <a class="btn-close" data-bs-dismiss="alert" aria-label="close" />}
</div>
+10 -11
View File
@@ -9,22 +9,22 @@ interface Person {
[key: string]: unknown
}
/** core/scss/_variables.scss `$avatar-sizes` map keys */
export type AvatarSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
interface Props {
src?: string
placeholder?: string | undefined
personId?: number
person?: Person | undefined
link?: boolean
dropdown?: boolean
size?: string | undefined
size?: AvatarSize | undefined
thumb?: boolean
class?: string
shape?: string
color?: string | undefined
square?: boolean
status?: string
statusText?: string
statusIcon?: string
statusLabel?: string
brand?: string
icon?: string | undefined
@@ -34,7 +34,7 @@ interface Props {
[key: string]: unknown
}
const { src: srcProp, placeholder: placeholderProp, personId, person: personProp, link: linkProp = false, dropdown, size, thumb, class: className, shape, color, square, status, statusText, statusIcon, statusLabel, brand, icon, base = '.', ...rest } = Astro.props
const { src: srcProp, placeholder: placeholderProp, personId, person: personProp, link: linkProp = false, size, thumb, class: className, shape, color, square, status, statusLabel, brand, icon, base = '.', ...rest } = Astro.props
let src = srcProp
let placeholder = placeholderProp
@@ -47,14 +47,13 @@ if (person) {
}
}
const link = linkProp || Boolean(dropdown)
const El = link ? 'a' : 'span'
const El = linkProp ? 'a' : 'span'
const classes = ['avatar', size && `avatar-${size}`, thumb && 'avatar-thumb', className, shape && `avatar-${shape}`, color && `bg-${color}-lt`, square && 'avatar-square']
---
<El class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} data-bs-toggle={dropdown ? 'dropdown' : undefined} {...rest}
>{status && <span class={`badge bg-${status}`}>{statusText ? statusText : statusIcon ? <Icon name={statusIcon} class="avatar-status-icon" /> : <span class="visually-hidden">{statusLabel ?? status}</span>}</span>}{
brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />
}{src ? null : placeholder ? placeholder : icon ? <Icon name={icon} class="avatar-icon" /> : <Icon name="user" class="avatar-icon" />}</El
<El class:list={classes} style={src ? `background-image: url(${base}/${src})` : undefined} {...rest}
>{status && <span class={`badge bg-${status}`} aria-label={statusLabel ?? status} />}{brand && <span class="avatar-brand" style={`background-image: url(${base}/static/brands/${brand}.svg);`} />}{
src ? null : placeholder ? placeholder : icon ? <Icon name={icon} class="avatar-icon" /> : <Icon name="user" class="avatar-icon" />
}</El
>
+2 -1
View File
@@ -3,6 +3,7 @@
// Pass children to override and render a custom list.
// NOTE: when `size` is omitted we pass NO size to Avatar — callers that omit size should not get avatar-N suffix classes.
import Avatar from './Avatar.astro'
import type { AvatarSize } from './Avatar.astro'
import people from '@data/people.json'
interface Person {
@@ -16,7 +17,7 @@ interface Props {
offset?: number | undefined
stacked?: boolean
/** avatar-list-{size} + forwarded to default Avatars */
size?: string
size?: AvatarSize | undefined
class?: string
/** placeholder avatar appended after the list */
text?: string
+2 -1
View File
@@ -1,9 +1,10 @@
---
import Icon from './Icon.astro'
import type { AvatarSize } from './Avatar.astro'
interface Props {
class?: string
size?: string
size?: AvatarSize | undefined
}
const { class: className, size } = Astro.props
+3 -5
View File
@@ -7,16 +7,14 @@ interface Props {
/** theme color the pattern ramps up to, e.g. 'primary' */
color?: string
size?: 'sm' | 'md' | 'lg' | 'xl'
/** element to render instead of div */
as?: string
class?: string
/** remaining attributes (style, data-*, …) are forwarded to the element */
[key: string]: unknown
}
const { pattern, color, size, as: Element = 'div', class: className, ...rest }: Props = Astro.props
const { pattern, color, size, class: className, ...rest }: Props = Astro.props
---
<Element class:list={[`bg-pattern-${pattern}`, color && `bg-pattern-${color}`, size && `bg-pattern-${size}`, className]} {...rest}>
<div class:list={[`bg-pattern-${pattern}`, color && `bg-pattern-${color}`, size && `bg-pattern-${size}`, className]} {...rest}>
<slot />
</Element>
</div>
+2 -17
View File
@@ -1,13 +1,5 @@
---
import Icon from './Icon.astro'
import Avatar from './Avatar.astro'
import people from '@data/people.json'
interface Person {
full_name?: string
photo?: string
[key: string]: unknown
}
interface Props {
text?: string
@@ -18,18 +10,11 @@ interface Props {
light?: boolean
class?: string
icon?: string
/** person-id — renders an inline avatar badge for people[personId - 1] */
personId?: number
/** addon text in a <span class="badge-addon"> */
addon?: string
addonColor?: string
}
const { text, color, scale, light, class: className, icon, personId, addon, addonColor } = Astro.props
const person = personId ? (people as Person[])[personId - 1] : undefined
const { text, color, scale, light, class: className, icon } = Astro.props
const classes = ['badge', scale && `badge-${scale}`, color && `bg-${color}${light ? '-lt' : ''} text-${color}${light ? '-lt' : ''}-fg`, className]
---
<span class:list={classes}>{icon && <Icon name={icon} />}{personId && <Avatar personId={personId} />}{text ? text : person?.full_name}{addon && <span class={`badge-addon ${addonColor ? `bg-${addonColor}` : ''}`}>{addon}</span>}</span>
<span class:list={classes}>{icon && <Icon name={icon} />}{text}</span>
+6 -30
View File
@@ -4,6 +4,9 @@
// TODO: color=false special case — pass no color prop instead.
import Icon from './Icon.astro'
/** core/scss/ui/_buttons.scss `.btn-{size}` modifier classes — 'md' is the default (no class emitted) */
type ButtonSize = 'sm' | 'md' | 'lg' | 'xl'
interface Props {
text?: string
href?: string
@@ -15,24 +18,13 @@ interface Props {
color?: string | undefined
outline?: boolean
ghost?: boolean
/** btn-{height} right after btn */
height?: string
size?: string
size?: ButtonSize | undefined
block?: boolean
disabled?: boolean
square?: boolean
loading?: boolean
action?: boolean
pill?: boolean
/** btn-link */
link?: boolean
class?: string
icon?: string
iconColor?: string
iconEnd?: string
iconOnly?: boolean
/** animated dots after the text */
dots?: boolean
/** data-bs-toggle="modal" data-bs-target="#modal-{modalId}" (modal-id param) */
modalId?: string
/** data-bs-toggle="toast" data-bs-target="#toast-{toastId}" (toast-id param) */
@@ -43,33 +35,18 @@ interface Props {
dropdown?: boolean
}
const { text = 'Button', href, external, element, type, id, color, outline, ghost, height, size, block, disabled, square, loading, action, pill, link, class: className, icon, iconColor, iconEnd, iconOnly, dots, modalId, toastId, dismiss, dropdown } = Astro.props
const { text = 'Button', href, external, element, type, id, color, outline, ghost, size, block, class: className, icon, iconColor, iconEnd, iconOnly, modalId, toastId, dismiss, dropdown } = Astro.props
// Without a real destination the control is an action, so render <button>; internal hrefs are prefixed with '/'.
const Element = element ?? (href ? 'a' : 'button')
const resolvedHref = href ? (external ? href : `/${href}`) : '#'
const classes = [
'btn',
height && `btn-${height}`,
color && `btn-${outline ? 'outline-' : ghost ? 'ghost-' : ''}${color}`,
disabled && 'disabled',
square && 'btn-square',
loading && 'btn-loading',
action && 'btn-action',
pill && 'btn-pill',
size && `btn-${size}`,
className,
block && 'w-100',
link && 'btn-link',
iconOnly && 'btn-icon',
]
const classes = ['btn', color && `btn-${outline ? 'outline-' : ghost ? 'ghost-' : ''}${color}`, size && size !== 'md' && `btn-${size}`, className, block && 'w-100', iconOnly && 'btn-icon']
---
<Element
href={Element === 'a' ? resolvedHref : undefined}
type={Element === 'button' ? (type ?? 'button') : undefined}
disabled={Element === 'button' && disabled ? true : undefined}
id={id}
class:list={classes}
target={external ? '_blank' : undefined}
@@ -81,6 +58,5 @@ const classes = [
>
{icon && <Icon name={icon} color={iconColor} />}
{!iconOnly && text}
{!iconOnly && dots && <span class="animated-dots" />}
{!iconOnly && iconEnd && <Icon name={iconEnd} class="icon-end" />}
</Element>
+2 -5
View File
@@ -4,17 +4,14 @@
interface Props {
/** use .btn-group-vertical instead of .btn-group */
vertical?: boolean
/** btn-group-{size}: sm | lg | xl */
size?: string
class?: string
role?: astroHTML.JSX.AriaRole
/** remaining attributes (aria-label, …) are forwarded */
[key: string]: unknown
}
const { vertical, size, class: className, role = 'group', ...rest } = Astro.props
const { vertical, class: className, ...rest } = Astro.props
---
<div class:list={[vertical ? 'btn-group-vertical' : 'btn-group', size && `btn-group-${size}`, className]} role={role} {...rest}>
<div class:list={[vertical ? 'btn-group-vertical' : 'btn-group', className]} role="group" {...rest}>
<slot />
</div>
+4 -2
View File
@@ -7,9 +7,11 @@ import type { HTMLTag } from 'astro/types'
// literally named `as` and silently falls back to untyped props.
type PolymorphicProps = { as?: HTMLTag }
/** core/scss/ui/_cards.scss `.card-{size}` body padding modifier classes */
type CardSize = 'sm' | 'md' | 'lg'
interface Props extends PolymorphicProps {
/** card-{size} body padding: sm | md | lg */
size?: string
size?: CardSize | undefined
class?: string
/** remaining attributes (id, action, data-*, …) are forwarded to the element */
[key: string]: unknown
+2 -2
View File
@@ -2,11 +2,11 @@
import Icon from './Icon.astro'
interface Props {
icon?: string
class?: string
}
const { icon = 'dots-vertical', class: className } = Astro.props
const { class: className } = Astro.props
const icon = 'dots-vertical'
---
<div class:list={['dropdown', className]}>
+2 -4
View File
@@ -2,14 +2,12 @@
// Card footer (.card-footer).
interface Props {
/** card-footer-transparent */
transparent?: boolean
class?: string
}
const { transparent, class: className } = Astro.props
const { class: className } = Astro.props
---
<div class:list={['card-footer', transparent && 'card-footer-transparent', className]}>
<div class:list={['card-footer', className]}>
<slot />
</div>
+2 -4
View File
@@ -9,15 +9,13 @@ type PolymorphicProps = { as?: HTMLTag }
interface Props extends PolymorphicProps {
title?: string
/** card-header-light */
light?: boolean
class?: string
}
const { title, as: TitleTag = 'h3', light, class: className }: Props = Astro.props
const { title, as: TitleTag = 'h3', class: className }: Props = Astro.props
---
<div class:list={['card-header', light && 'card-header-light', className]}>
<div class:list={['card-header', className]}>
{title && <TitleTag class:list={['card-title']}>{title}</TitleTag>}
<slot />
</div>
+1 -1
View File
@@ -5,7 +5,7 @@ import Icon from './Icon.astro'
interface Props {
icon?: string
/** card-stamp-{size}; only 'lg' exists in SCSS (13rem instead of 7rem) */
size?: string
size?: 'lg' | undefined
/** bg-{color} on the icon wrapper; SCSS default is secondary */
color?: string
/** text-{textColor} on the icon wrapper (e.g. color="white" textColor="primary") */
+4 -45
View File
@@ -1,67 +1,26 @@
---
// Self-contained carousel (.carousel). Default slot holds the .carousel-item elements
// (the caller marks the first one "active" — see CarouselCard.astro / hero/Side.astro);
// indicators/controls are generated from props. A "controls" slot overrides the default
// icon-span controls with custom markup (e.g. an <Icon>-based pair).
// a "controls" slot renders custom prev/next markup (e.g. an <Icon>-based pair).
interface Props {
id?: string
/** slide count, used to generate indicator buttons */
slideCount: number
fade?: boolean
/** data-bs-interval in ms, or false to disable autoplay */
interval?: number | false
indicators?: boolean
indicatorsVariant?: 'dot' | 'thumb'
indicatorsVertical?: boolean
/** ratio ratio-4x3 on each indicator button, typically paired with indicatorsVariant="thumb" */
indicatorsThumbRatio?: boolean
/** background-image per slide, used when indicatorsVariant="thumb" */
indicatorsImages?: string[]
controls?: boolean
class?: string
/** remaining attributes forwarded to the element */
[key: string]: unknown
}
const { id, slideCount, fade, interval, indicators, indicatorsVariant, indicatorsVertical, indicatorsThumbRatio, indicatorsImages, controls, class: className, ...rest } = Astro.props
const { id, interval, class: className, ...rest } = Astro.props
const target = id ? `#${id}` : undefined
const slideIndexes = Array.from({ length: slideCount }, (_, i) => i)
const hasCustomControls = Astro.slots.has('controls')
---
<div id={id} class:list={['carousel', 'slide', fade && 'carousel-fade', className]} data-bs-ride="carousel" data-bs-interval={interval === false ? 'false' : interval} {...rest}>
{
indicators && (
<div class:list={['carousel-indicators', indicatorsVertical && 'carousel-indicators-vertical', indicatorsVariant === 'dot' && 'carousel-indicators-dot', indicatorsVariant === 'thumb' && 'carousel-indicators-thumb']}>
{slideIndexes.map((i) => (
<button type="button" data-bs-target={target} data-bs-slide-to={i} class:list={[indicatorsThumbRatio && 'ratio ratio-4x3', i === 0 && 'active']} style={indicatorsVariant === 'thumb' && indicatorsImages?.[i] ? `background-image: url(${indicatorsImages[i]})` : undefined} />
))}
</div>
)
}
<div id={id} class:list={['carousel', 'slide', className]} data-bs-ride="carousel" data-bs-interval={interval === false ? 'false' : interval} {...rest}>
<div class="carousel-inner">
<slot />
</div>
{
hasCustomControls ? (
<slot name="controls" />
) : (
controls && (
<Fragment>
<a class="carousel-control-prev" href={target} role="button" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true" />
<span class="visually-hidden">Previous</span>
</a>
<a class="carousel-control-next" href={target} role="button" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true" />
<span class="visually-hidden">Next</span>
</a>
</Fragment>
)
)
}
{hasCustomControls && <slot name="controls" />}
</div>
+2 -22
View File
@@ -5,36 +5,21 @@ interface Props {
id?: string | undefined;
type?: string;
color?: string | undefined;
height?: number;
small?: boolean;
wide?: boolean;
data?: string | number;
percentage?: string | number;
/**
* Sparklines are typically decorative, sitting next to a visible stat
* number that already conveys the value — so they're hidden from
* assistive tech by default. Set to `false` (with `label`) when the
* sparkline is the only representation of the data.
*/
decorative?: boolean;
/** Accessible name, used only when `decorative` is explicitly `false`. */
label?: string;
}
const {
id,
type = 'bar',
color = 'primary',
height: heightProp,
small,
wide,
data: dataProp,
percentage,
decorative = true,
label,
} = Astro.props;
const height = heightProp ?? (small ? 1.5 : 2.5);
const height = small ? 1.5 : 2.5;
const heightPx = Math.round(height * 16);
const data = percentage ?? dataProp;
@@ -45,17 +30,12 @@ const chartType = type === 'donut' ? 'radialBar' : type;
const classes = [
'chart-sparkline',
isSquare && 'chart-sparkline-square',
wide && 'chart-sparkline-wide',
small && 'chart-sparkline-sm',
]
const seriesData = String(data ?? '').split(',').map(Number);
const chartKey = `sparkline-${id}`;
const ariaHidden = decorative ? true : undefined;
const ariaRole = decorative ? undefined : 'img';
const ariaLabel = decorative ? undefined : (label ?? 'Chart');
const chartOptions = id
? {
chart: {
@@ -87,7 +67,7 @@ const chartOptions = id
: undefined;
---
{id && <div class:list={classes} id={chartKey} role={ariaRole} aria-label={ariaLabel} aria-hidden={ariaHidden} />}
{id && <div class:list={classes} id={chartKey} aria-hidden="true" />}
{
id && (
<CaptureScript>
+3 -5
View File
@@ -5,15 +5,14 @@ import CaptureScript from '../components/CaptureScript.astro'
interface Props {
value?: string
id?: string | number
alpha?: boolean
format?: string | false
swatchesOnly?: boolean
class?: string
/** Accessible name for the input; falls back to a generic label when the caller doesn't wrap this in a labelled FormGroup */
ariaLabel?: string
}
const { value, id = 'default', alpha = false, format = false, swatchesOnly, class: className, ariaLabel } = Astro.props
const { value, id = 'default', format = false, class: className, ariaLabel } = Astro.props
const alpha = false
const colors = site.colors as Record<string, { prop: string }>
const swatchProps = Object.values(colors).map((color) => color.prop)
@@ -25,7 +24,7 @@ const colorpickerSelector = `#colorpicker-${id}`
<input type="text" class={`form-control d-block${className ? ` ${className}` : ''}`} id={colorpickerId} value={value} aria-label={ariaLabel ?? 'Color value'} />
<CaptureScript>
<!-- BEGIN COLORPICKER -->
<script is:inline define:vars={{ colorpickerId, colorpickerSelector, alpha, format, swatchesOnly, swatchProps }}>
<script is:inline define:vars={{ colorpickerId, colorpickerSelector, alpha, format, swatchProps }}>
function initColorpicker() {
window.tabler_colorpicker ??= {}
@@ -40,7 +39,6 @@ const colorpickerSelector = `#colorpicker-${id}`
selectInput: false,
alpha,
...(format ? { format } : {}),
...(swatchesOnly ? { swatchesOnly: true } : {}),
swatches,
})
window.tabler_colorpicker[colorpickerId] = colorpickerSelector
+2 -2
View File
@@ -5,7 +5,6 @@ import CaptureScript from '../components/CaptureScript.astro';
interface Props {
id?: string;
value?: string;
placeholder?: string;
class?: string;
/** 'icon' | 'icon-prepend' | undefined (plain) */
layout?: string;
@@ -15,12 +14,13 @@ interface Props {
const {
id,
value = '2020-06-20',
placeholder = 'Select a date',
class: className,
layout,
inline,
} = Astro.props;
const placeholder = 'Select a date';
const chevronLeft =
'<!-- Download SVG icon from http://tabler.io/icons/icon/chevron-left -->\n\t<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false" class="icon"><path d="M15 6l-6 6l6 6" /></svg>';
const chevronRight =
+2 -2
View File
@@ -2,10 +2,10 @@
interface Props {
id?: string
label?: string
value?: string
}
const { id, label = 'Select time range', value = 'Last 7 days' } = Astro.props
const { id, label = 'Select time range' } = Astro.props
const value = 'Last 7 days'
---
<div class="dropdown">
+3 -26
View File
@@ -11,12 +11,10 @@ interface Props {
arrow?: boolean
dark?: boolean
class?: string
menu?: string[]
check?: boolean
radio?: boolean
people?: boolean
flag?: boolean
type?: string
header?: boolean
icons?: boolean
badge?: boolean
@@ -25,38 +23,17 @@ interface Props {
separated?: boolean
}
const { right, show, arrow, dark, class: className, menu, check, radio, people: showPeople, flag: showFlags, type, header, icons, badge, active, disabled, separated } = Astro.props
const { right, show, arrow, dark, class: className, check, radio, people: showPeople, flag: showFlags, header, icons, badge, active, disabled, separated } = Astro.props
const classes = ['dropdown-menu', right && 'dropdown-menu-end', show && 'dropdown-menu-demo', arrow && 'dropdown-menu-arrow', className]
const menuItems = menu
const peopleItems = (people as { id: string; full_name: string }[]).slice(0, 5)
const countryItems = (countries as { name: string; flag: string }[]).slice(0, 5)
---
<div class:list={classes} data-bs-theme={dark ? 'dark' : undefined}>
{
menuItems ? (
menuItems.map((item) =>
item === '|' ? (
<div class="dropdown-divider" />
) : item.includes('h:') ? (
<h3 class="dropdown-header">{item.split('h:').join('')}</h3>
) : item.includes('a:') ? (
<button type="button" class="dropdown-item active">
{item.split('a:').join('')}
</button>
) : item.includes('d:') ? (
<button type="button" class="dropdown-item text-danger">
{item.split('d:').join('')}
</button>
) : (
<button type="button" class="dropdown-item">
{item}
</button>
),
)
) : check || radio ? (
check || radio ? (
[1, 2, 3].map((i) => (
<label class="dropdown-item">
<input class="form-check-input m-0 me-2" type={radio ? 'radio' : 'checkbox'} name={radio ? 'dropdown-menu-radio' : undefined} /> Option {i}
@@ -74,7 +51,7 @@ const countryItems = (countries as { name: string; flag: string }[]).slice(0, 5)
<Flag flag={country.flag} size="xs" /> {country.name}
</button>
))
) : type === 'text' ? null : (
) : (
<>
{header && <span class="dropdown-header">Dropdown header</span>}
<button type="button" class="dropdown-item">
+2 -2
View File
@@ -6,10 +6,10 @@ interface Props {
custom?: boolean
text?: string
description?: string
label?: string
}
const { id = 'default', multiple, custom, text = 'Text', description = 'Description', label = 'Upload file' } = Astro.props
const { id = 'default', multiple, custom, text = 'Text', description = 'Description' } = Astro.props
const label = 'Upload file'
const dropzoneId = `dropzone-${id}`
const dropzoneSelector = `#dropzone-${id}`
+2 -3
View File
@@ -6,7 +6,6 @@ import Illustration from './Illustration.astro'
interface Props {
icon?: string
height?: number | string
bordered?: boolean
class?: string
/** illustration file name, e.g. "computer-fix.svg" */
illustration?: string | undefined
@@ -18,9 +17,9 @@ interface Props {
buttonIcon?: string
}
const { icon = 'mood-sad', height = 256, bordered, class: className, illustration, iconText, title = 'No results found', subtitle = "Try adjusting your search or filter to find what you're looking for.", buttonText = 'Search again', buttonIcon = 'search' } = Astro.props
const { icon = 'mood-sad', height = 256, class: className, illustration, iconText, title = 'No results found', subtitle = "Try adjusting your search or filter to find what you're looking for.", buttonText = 'Search again', buttonIcon = 'search' } = Astro.props
const classes = ['empty', bordered && 'empty-bordered', className]
const classes = ['empty', className]
---
<div class:list={classes}>
+4 -1
View File
@@ -1,7 +1,10 @@
---
import type { AvatarSize } from './Avatar.astro'
interface Props {
flag?: string | undefined
size?: string
/** core/scss/_variables.scss `$flag-sizes` (aliased to `$avatar-sizes`) */
size?: AvatarSize | undefined
class?: string
label?: string | undefined
}
+2 -3
View File
@@ -2,13 +2,12 @@
interface Props {
text?: string
position?: string
color?: string
class?: string
}
const { text = 'Label', position, color, class: className } = Astro.props
const { text = 'Label', position, class: className } = Astro.props
const classes = ['hr-text', position && `hr-text-${position.toLowerCase()}`, color && `text-${color}`, className]
const classes = ['hr-text', position && `hr-text-${position.toLowerCase()}`, className]
---
<div class:list={classes}>{text}</div>
+4 -1
View File
@@ -1,12 +1,15 @@
---
import icons from '@data/icons.json'
/** core/scss/ui/_icons.scss `.icon-{size}` modifier classes */
export type IconSize = 'sm' | 'md' | 'lg'
interface Props {
name: string
type?: 'outline' | 'filled'
class?: string | undefined
color?: string | undefined
size?: string
size?: IconSize | undefined
inline?: boolean
}
+2 -3
View File
@@ -4,13 +4,12 @@ import Icon from './Icon.astro'
interface Props {
pills?: boolean
tabs?: boolean
header?: boolean
class?: string
}
const { pills, tabs, header, class: className } = Astro.props
const { pills, tabs, class: className } = Astro.props
const classes = ['nav', pills ? 'nav-pills' : tabs ? 'nav-tabs' : undefined, pills && header ? 'card-header-pills' : tabs && header ? 'card-header-tabs' : undefined, className]
const classes = ['nav', pills ? 'nav-pills' : tabs ? 'nav-tabs' : undefined, className]
---
<ul class:list={classes}>
+5 -11
View File
@@ -1,39 +1,33 @@
---
import Icon from './Icon.astro'
import { includeArgCount } from '@shared/lib/include-args'
interface Props {
items?: string[]
icons?: string[]
disabled?: number[]
hover?: string
default?: number
vertical?: boolean
size?: string
/** core/scss/ui/_segmented.scss `.nav-{size}` modifier classes */
size?: 'sm' | 'lg' | undefined
fullWidth?: boolean
name?: string
class?: string
}
const { items, icons, disabled, hover = '', default: defaultIndex = 1, vertical, size, fullWidth, name, class: className } = Astro.props
// When `size` is omitted, append `nav-{argCount}` (e.g. nav-1, nav-2). An explicit size uses nav-sm/nav-lg.
const includeArgKeys = ['items', 'icons', 'disabled', 'hover', 'default', 'vertical', 'size', 'fullWidth', 'class', 'name'] as const
const argCount = includeArgCount(Astro.props as Record<string, unknown>, includeArgKeys)
const sizeToken = size ? `nav-${size}` : `nav-${argCount}`
const { items, icons, disabled, default: defaultIndex = 1, vertical, size, fullWidth, name, class: className } = Astro.props
const itemsArr = items ?? []
const iconsArr = icons ?? []
const count = Math.max(itemsArr.length, iconsArr.length)
const navClasses = ['nav', 'nav-segmented', vertical && 'nav-segmented-vertical', sizeToken, fullWidth && 'w-100', className]
const navClasses = ['nav', 'nav-segmented', vertical && 'nav-segmented-vertical', size && `nav-${size}`, fullWidth && 'w-100', className]
const rows = Array.from({ length: count }, (_, i) => {
const forloopIndex = i + 1
const index = String(forloopIndex)
const isDisabled = disabled?.includes(forloopIndex) ?? false
const isDefault = forloopIndex === defaultIndex
const linkClasses = ['nav-link', isDisabled && 'disabled', isDefault && !name && 'active', hover === index && 'hover']
const linkClasses = ['nav-link', isDisabled && 'disabled', isDefault && !name && 'active']
return { forloopIndex, index, isDisabled, isDefault, linkClasses, icon: iconsArr[i], item: itemsArr[i] }
})
---
+6 -8
View File
@@ -2,12 +2,10 @@
// Offcanvas container (.offcanvas). Renders inline at the call site (unlike Modal, which drains to the end of body).
interface Props {
/** offcanvas-{direction}: start | end | top | bottom */
direction?: string
/** responsive variant offcanvas-{size} (lg | xl | xxl) — replaces the base .offcanvas class */
size?: string
/** offcanvas-narrow (20rem width) */
narrow?: boolean
/** core/scss/bootstrap/_offcanvas.scss `.offcanvas-{direction}` modifier classes */
direction?: 'start' | 'end' | 'top' | 'bottom' | undefined
/** responsive variant offcanvas-{size} ($grid-breakpoints minus xs) — replaces the base .offcanvas class */
size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | undefined
show?: boolean
class?: string
/** defaults to "-1" when not provided */
@@ -18,11 +16,11 @@ interface Props {
[key: string]: unknown
}
const { direction, size, narrow, show, class: className, tabindex, role, ...rest } = Astro.props
const { direction, size, show, class: className, tabindex, role, ...rest } = Astro.props
---
<!-- BEGIN OFFCANVAS -->
<div class:list={[size ? `offcanvas-${size}` : 'offcanvas', direction && `offcanvas-${direction}`, narrow && 'offcanvas-narrow', show && 'show', className]} tabindex={tabindex ?? '-1'} role={role ?? 'dialog'} {...rest}>
<div class:list={[size ? `offcanvas-${size}` : 'offcanvas', direction && `offcanvas-${direction}`, show && 'show', className]} tabindex={tabindex ?? '-1'} role={role ?? 'dialog'} {...rest}>
<slot />
</div>
<!-- END OFFCANVAS -->
-13
View File
@@ -1,13 +0,0 @@
---
// Offcanvas footer (.offcanvas-footer).
interface Props {
class?: string
}
const { class: className } = Astro.props
---
<div class:list={['offcanvas-footer', className]}>
<slot />
</div>
+4 -1
View File
@@ -1,8 +1,11 @@
---
import type { AvatarSize } from './Avatar.astro'
interface Props {
payment?: string
dark?: boolean
size?: string
/** core/scss/_variables.scss `$payment-sizes` (aliased to `$avatar-sizes`) */
size?: AvatarSize | undefined
class?: string
label?: string | undefined
}
+4 -1
View File
@@ -5,12 +5,15 @@ interface Photo {
title?: string
}
/** core/scss/_variables.scss `$aspect-ratios` map keys */
type PhotoRatio = '1x1' | '2x1' | '1x2' | '3x1' | '1x3' | '4x1' | '1x4' | '4x3' | '3x4' | '16x9' | '9x16' | '21x9' | '9x21'
interface Props {
photo: Photo
/** background param — plain <div> with only the background-image (no ratio class) */
background?: boolean
/** ratio param — img-responsive img-responsive-{ratio} wrapper */
ratio?: string
ratio?: PhotoRatio | undefined
class?: string
}
+6 -4
View File
@@ -1,10 +1,12 @@
---
/** core/scss/ui/_progress.scss `.progress-{size}` modifier classes */
export type ProgressSize = 'sm' | 'lg' | 'xl'
interface Props {
value?: number | string | undefined
values?: (string | number)[]
color?: string | undefined
colors?: string[]
size?: string | undefined
size?: ProgressSize | undefined
class?: string
width?: string
id?: string
@@ -14,11 +16,11 @@ interface Props {
showValue?: boolean
}
const { value, values, color, colors: colorsProp, size, class: className, width, id, indeterminate, striped, animated, showValue } = Astro.props
const { value, values, color, size, class: className, width, id, indeterminate, striped, animated, showValue } = Astro.props
const percentage = value !== undefined && value !== null && `${value}` !== '' ? `${value}`.split('%').join('') : '38'
const colors = colorsProp ?? (color ? [color] : ['blue', 'red', 'green', 'yellow', 'dark'])
const colors = color ? [color] : ['blue', 'red', 'green', 'yellow', 'dark']
const valueList = values
const classes = ['progress', size && `progress-${size}`, className]
+2 -11
View File
@@ -1,6 +1,5 @@
---
import Progress from './Progress.astro'
import Flag from './Flag.astro'
import { parsePercentage } from '@shared/lib/string-format'
interface Props {
@@ -8,24 +7,16 @@ interface Props {
color?: string
class?: string
text?: string
flag?: string
showValue?: boolean
}
const { value, color = 'primary-lt', class: className, text, flag, showValue } = Astro.props
const { value, color = 'primary-lt', class: className, text, showValue } = Astro.props
const percentage = parsePercentage(value)
---
<div class={`progressbg${className ? ` ${className}` : ''}`}>
<Progress value={percentage} class="progressbg-progress" color={color} />
{
text && (
<div class="progressbg-text">
{flag && <Flag flag={flag} class="me-2" size="xs" />}
{text}
</div>
)
}
{text && <div class="progressbg-text">{text}</div>}
{showValue && <div class="progressbg-value">{percentage}%</div>}
</div>
+2 -1
View File
@@ -1,13 +1,14 @@
---
// Forward `size` only when explicitly provided.
import Progress from './Progress.astro'
import type { ProgressSize } from './Progress.astro'
interface Props {
label?: string
description?: string
value?: number | string
color?: string
size?: string
size?: ProgressSize | undefined
class?: string
}
+2 -2
View File
@@ -4,14 +4,14 @@ import CaptureScript from '../components/CaptureScript.astro';
interface Props {
min?: number;
max?: number;
step?: number;
value?: string | number;
id?: string;
connect?: boolean;
class?: string;
}
const { min = 0, max = 100, step = 10, value = 50, id, connect = false, class: className } = Astro.props;
const { min = 0, max = 100, value = 50, id, connect = false, class: className } = Astro.props;
const step = 10;
const values = String(value).split(',');
const size = values.length;
+2 -1
View File
@@ -1,12 +1,13 @@
---
import icons from '@data/icons.json'
import CaptureScript from '../components/CaptureScript.astro'
import type { IconSize } from './Icon.astro'
interface Props {
id?: string
icon?: string
color?: string
size?: string
size?: IconSize | undefined
value?: number
}
+3 -7
View File
@@ -4,18 +4,14 @@ import Icon from './Icon.astro'
interface Props {
text?: string
top?: boolean
left?: boolean
bottom?: boolean
bookmark?: boolean
color?: string
filled?: boolean
}
const { text, top, left, bottom, bookmark, color, filled } = Astro.props
const { text, top, color } = Astro.props
const classes = ['ribbon', top && 'ribbon-top', left && 'ribbon-start', bottom && 'ribbon-bottom', bookmark && 'ribbon-bookmark', color && `bg-${color}`]
const classes = ['ribbon', top && 'ribbon-top', color && `bg-${color}`]
---
<div class:list={classes}>
{text ? text : <Icon name="star" type={filled ? 'filled' : 'outline'} />}
{text ? text : <Icon name="star" />}
</div>
+5 -7
View File
@@ -1,16 +1,14 @@
---
// "Less -> More" gradient legend, e.g. for a choropleth map's color scale.
interface Props {
/** number of swatches */
steps?: number
/** theme color the swatches ramp up to, e.g. 'primary' */
color?: string
minLabel?: string
maxLabel?: string
class?: string
}
const { steps = 10, color = 'primary', minLabel = 'Less', maxLabel = 'More', class: className } = Astro.props
const { class: className } = Astro.props
const steps = 10
const color = 'primary'
const minLabel = 'Less'
const maxLabel = 'More'
const items = Array.from({ length: steps }, (_, i) => i + 1)
---
+3 -9
View File
@@ -10,29 +10,24 @@ import CaptureScript from '../components/CaptureScript.astro';
interface Props {
id?: string;
key?: string;
value?: string;
class?: string;
state?: string;
placeholder?: string;
indicator?: string;
multiple?: boolean;
values?: string[];
showSearch?: boolean;
}
const {
id: idProp,
key: keyProp,
value = '',
class: className,
state,
placeholder,
indicator,
multiple,
values,
showSearch,
} = Astro.props;
const value = '';
const id = idProp ?? keyProp;
const key = keyProp ?? 'people';
const data = (selects as Record<string, any>)[key] ?? {};
@@ -43,7 +38,7 @@ const selectClass = [
state && `is-${state}`,
]
const isMultiple = Boolean(multiple || data.multiple);
const isMultiple = Boolean(data.multiple);
interface Person {
id: string;
@@ -125,7 +120,7 @@ const selectId = id ? `select-${id}` : undefined;
id && (
<CaptureScript>
<!-- BEGIN SELECT -->
<script is:inline define:vars={{ selectId, showSearch }}>
<script is:inline define:vars={{ selectId }}>
function initSelect() {
window.tabler_select ??= {};
@@ -140,7 +135,6 @@ const selectId = id ? `select-${id}` : undefined;
(window.tabler_select[selectId] = new TomSelect(document.getElementById(selectId), {
copyClassesToDropdown: false,
dropdownParent: 'body',
...(showSearch === false ? { controlInput: null } : {}),
render: {
item: renderOption,
option: renderOption,
+6 -14
View File
@@ -1,23 +1,15 @@
---
// With explicit `size`: `spinner-{type}-{size}`. Without `size`: `spinner-{type}-{argCount}` (e.g. spinner-border-2).
import { includeArgCount } from '@shared/lib/include-args'
interface Props {
element?: 'div' | 'span'
type?: string
type?: 'border' | 'grow'
color?: string
size?: string
/** core/scss/bootstrap/_spinners.scss `.spinner-{type}-{size}` — only 'sm' exists */
size?: 'sm' | undefined
class?: string
}
const { element: Element = 'div', type = 'border', color, size, class: className } = Astro.props
const { type = 'border', color, size, class: className } = Astro.props
const includeArgKeys = ['element', 'type', 'color', 'size', 'class'] as const
const argCount = includeArgCount(Astro.props as Record<string, unknown>, includeArgKeys)
// include['size'] → explicit value, else the arg count meta-property.
const sizeValue = size !== undefined ? size : argCount || undefined
const classes = [`spinner-${type}`, color && `text-${color}`, sizeValue && `spinner-${type}-${sizeValue}`, className]
const classes = [`spinner-${type}`, color && `text-${color}`, size && `spinner-${type}-${size}`, className]
---
<Element class:list={classes} role="status" />
<div class:list={classes} role="status"></div>
+4 -8
View File
@@ -4,15 +4,11 @@ interface Props {
count?: number | string
active?: number | string
numbers?: boolean
color?: string
size?: string
showTooltip?: boolean
showTitle?: boolean
}
const { count = 4, active = 3, numbers, color, size, showTooltip, showTitle } = Astro.props
const { count = 4, active = 3, numbers } = Astro.props
const classes = ['steps', numbers && 'steps-counter', color && `steps-${color}`, size && `steps-${size}`]
const classes = ['steps', numbers && 'steps-counter']
const activeNum = Number(active)
const total = Number(count)
@@ -30,8 +26,8 @@ const steps = Array.from({ length: total }, (_, i) => i + 1)
const fallbackLabel = `Step ${i}${isCurrent ? ' (current)' : isDone ? ' (completed)' : ''}`
return (
<li class:list={itemClass}>
<Element href={isFuture ? undefined : '#'} aria-current={isCurrent ? 'step' : undefined} data-bs-toggle={showTooltip ? 'tooltip' : undefined} title={showTooltip ? `Step ${i} description` : undefined}>
{showTitle ? `Step ${i}` : <span class="visually-hidden">{fallbackLabel}</span>}
<Element href={isFuture ? undefined : '#'} aria-current={isCurrent ? 'step' : undefined}>
<span class="visually-hidden">{fallbackLabel}</span>
</Element>
</li>
)
+7 -13
View File
@@ -3,27 +3,21 @@ import Icon from './Icon.astro'
interface Props {
icon?: string
iconB?: string
iconAColor?: string
iconBColor?: string
iconBClass?: string
variant?: string
active?: boolean
/** accessible name announced alongside the pressed state, e.g. "Favorite" */
label?: string
}
const { icon = 'heart', iconB, iconAColor = 'muted', iconBColor = 'red', iconBClass, variant, active, label = 'Favorite' } = Astro.props
const { icon = 'heart', iconBColor = 'red', variant } = Astro.props
const resolvedIconB = iconB ?? icon ?? 'heart'
// star/heart force the filled variant; otherwise use the passed class.
const resolvedIconBClass = icon === 'star' || icon === 'heart' ? 'icon-filled' : iconBClass
const resolvedIconB = icon ?? 'heart'
// star/heart force the filled variant; otherwise no extra class.
const resolvedIconBClass = icon === 'star' || icon === 'heart' ? 'icon-filled' : undefined
const buttonClass = ['switch-icon', variant && `switch-icon-${variant}`, active && 'active']
const buttonClass = ['switch-icon', variant && `switch-icon-${variant}`]
---
<button type="button" class:list={buttonClass} data-bs-toggle="switch-icon" aria-pressed={active ? 'true' : 'false'} aria-label={label}>
<span class={`switch-icon-a text-${iconAColor}`}>
<button type="button" class:list={buttonClass} data-bs-toggle="switch-icon" aria-pressed="false" aria-label="Favorite">
<span class="switch-icon-a text-muted">
<Icon name={icon} />
</span>
<span class={`switch-icon-b text-${iconBColor}`}>
+2 -7
View File
@@ -14,17 +14,16 @@ interface Props {
avatars?: boolean
mobile?: boolean
buttons?: boolean
nowrap?: boolean
}
const { card, limit = 5, stripped, offset, avatars, mobile, buttons, nowrap } = Astro.props
const { card, limit = 5, stripped, offset, avatars, mobile, buttons } = Astro.props
const roles = ['User', 'Admin', 'Owner']
const start = offset ?? 0
const rows = (people as Record<string, any>[]).slice(start, start + limit)
const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', card && 'card-table', stripped && 'table-striped', nowrap && 'table-nowrap']
const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', card && 'card-table', stripped && 'table-striped']
---
<div class="table-responsive">
@@ -38,8 +37,6 @@ const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', car
<th>Role</th>
{nowrap && <th />}
<th class="w-1"></th>
</tr>
</thead>
@@ -90,8 +87,6 @@ const tableClasses = ['table', 'table-vcenter', mobile && 'table-mobile-md', car
{role}
</td>
{nowrap && <td>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi, commodi cupiditate debitis deserunt expedita hic incidunt iste modi molestiae nesciunt non nostrum perferendis perspiciatis placeat praesentium quaerat quo repellendus, voluptates.</td>}
<td>
{buttons ? (
<ButtonList class="flex-nowrap">
+2 -9
View File
@@ -2,7 +2,6 @@
import Icon from './Icon.astro'
import Flag from './Flag.astro'
import Avatar from './Avatar.astro'
import Payment from './Payment.astro'
import Badge from './Badge.astro'
interface Person {
@@ -16,8 +15,6 @@ interface Props {
flag?: string | undefined
icon?: string
person?: Person
personId?: number
payment?: string
status?: string
legend?: string
checkbox?: boolean
@@ -25,7 +22,7 @@ interface Props {
badge?: string | number
}
const { text, flag, icon, person, personId, payment, status, legend, checkbox, checked, badge } = Astro.props
const { text, flag, icon, person, status, legend, checkbox, checked, badge } = Astro.props
---
<span class="tag">
@@ -33,13 +30,9 @@ const { text, flag, icon, person, personId, payment, status, legend, checkbox, c
flag ? (
<Flag flag={flag} size="xxs" class="tag-flag" />
) : icon ? (
<Icon name={icon} size="xxs" class="tag-icon" />
<Icon name={icon} size="sm" class="tag-icon" />
) : person ? (
<Avatar person={person} size="xxs" class="tag-avatar" />
) : personId ? (
<Avatar personId={personId} size="xxs" class="tag-avatar" />
) : payment ? (
<Payment payment={payment} size="xxs" class="tag-payment" />
) : status ? (
<Badge color={status} class="tag-status badge-dot" text="" />
) : legend ? (
+10 -16
View File
@@ -5,16 +5,12 @@ import { requireIndex } from '@shared/lib/array'
interface Props {
toastId?: string
/** people index, 0-based (default 2 → Mallory Hulme) */
personId?: number
show?: boolean
hideHeader?: boolean
cookies?: boolean
date?: string
text?: string
}
const { toastId = 'simple', personId = 2, show, hideHeader, cookies, date = '11 mins ago', text = 'Hello, world! This is a toast message.' } = Astro.props
const { toastId = 'simple', show, cookies, text = 'Hello, world! This is a toast message.' } = Astro.props
interface Person {
full_name?: string
@@ -22,20 +18,18 @@ interface Person {
[key: string]: unknown
}
const person = requireIndex(people as Person[], personId)
const date = '11 mins ago'
/** people index, 0-based (default 2 → Mallory Hulme) */
const person = requireIndex(people as Person[], 2)
---
<div class:list={['toast', show && 'show']} id={`toast-${toastId}`} role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="false">
{
!hideHeader && (
<div class="toast-header">
<Avatar person={person} class="me-2" size="xs" />
<strong class="me-auto">{person.full_name}</strong>
<small>{date}</small>
<button type="button" class="ms-2 btn-close" data-bs-dismiss="toast" aria-label="Close" />
</div>
)
}
<div class="toast-header">
<Avatar person={person} class="me-2" size="xs" />
<strong class="me-auto">{person.full_name}</strong>
<small>{date}</small>
<button type="button" class="ms-2 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
{
cookies ? (
+7 -8
View File
@@ -4,20 +4,19 @@ import { capitalize } from '@shared/lib/string-format'
interface Props {
type?: 'checkbox' | 'radio'
checked?: boolean
disabled?: boolean
/** Switch mode (prop name isSwitch; `switch` is reserved). */
switch?: boolean
title?: string | false
name?: string
inline?: boolean
size?: string
empty?: boolean
/** core/scss/ui/forms/_form-check.scss `.form-switch-{size}` — only 'lg' exists */
size?: 'lg' | undefined
titleOn?: string
titleOff?: string
class?: string
}
const { type = 'checkbox', checked = false, disabled = false, switch: isSwitch = false, title: titleProp = false, name, inline, size, empty: isEmpty = false, titleOn, titleOff, class: className } = Astro.props
const { type = 'checkbox', checked = false, switch: isSwitch = false, title: titleProp = false, name, size, titleOn, titleOff, class: className } = Astro.props
const disabled = false
let title = titleProp
if (!title) {
@@ -32,9 +31,9 @@ if (!title) {
title = t
}
const labelClasses = ['form-check', inline && 'form-check-inline', isSwitch && 'form-switch', isSwitch && size && `form-switch-${size}`, className]
const labelClasses = ['form-check', isSwitch && 'form-switch', isSwitch && size && `form-switch-${size}`, className]
const inputClasses = ['form-check-input', isEmpty && 'position-static']
const inputClasses = ['form-check-input']
---
<label class:list={labelClasses}>
@@ -46,7 +45,7 @@ const inputClasses = ['form-check-input', isEmpty && 'position-static']
<span class="form-check-label form-check-label-off">{titleOff}</span>
</Fragment>
) : (
!isEmpty && <span class="form-check-label">{title}</span>
<span class="form-check-label">{title}</span>
)
}
</label>
+3 -6
View File
@@ -3,25 +3,22 @@ import Icon from '../Icon.astro'
interface Props {
icon?: string
iconClass?: string
class?: string
prepend?: boolean
type?: string
value?: string
light?: boolean
rounded?: boolean
inputClass?: string
ariaLabel?: string
readonly?: boolean
placeholder?: string
loader?: boolean
}
const { icon = 'search', iconClass, class: className, prepend, type = 'text', value = '', light, rounded, inputClass, ariaLabel, readonly, placeholder = 'Search…', loader } = Astro.props
const { icon = 'search', class: className, prepend, type = 'text', value = '', rounded, ariaLabel, readonly, placeholder = 'Search…', loader } = Astro.props
const wrapperClass = ['input-icon', className]
const addonClass = ['input-icon-addon', iconClass]
const controlClass = ['form-control', light && 'form-control-light', rounded && 'form-control-rounded', inputClass]
const addonClass = ['input-icon-addon']
const controlClass = ['form-control', rounded && 'form-control-rounded']
---
<div class:list={wrapperClass}>
+2 -2
View File
@@ -1,14 +1,14 @@
---
// IMask initializes from the data-mask attributes (tabler.js).
interface Props {
name?: string
mask?: string
visible?: boolean
placeholder?: string
reverse?: boolean
}
const { name = 'mask', mask = '00/00/0000', visible, placeholder, reverse } = Astro.props
const { mask = '00/00/0000', visible, placeholder, reverse } = Astro.props
const name = 'mask'
---
<input type="text" name={`input-${name}`} class="form-control" data-mask={mask} data-mask-visible={visible ? 'true' : undefined} placeholder={placeholder ?? mask} data-mask-reverse={reverse ? 'true' : undefined} autocomplete="off" />