banhaten 0.4.0 → 0.6.0

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.
Files changed (214) hide show
  1. package/CHANGELOG.md +78 -1
  2. package/CONTRIBUTING.md +6 -4
  3. package/README.md +4 -2
  4. package/docs/design-spacing.md +13 -0
  5. package/docs/design-system/README.md +2 -0
  6. package/docs/design-system/appearances/default.md +1 -1
  7. package/docs/design-system/appearances/rounded.md +1 -1
  8. package/docs/design-system/appearances/sharp.md +1 -1
  9. package/docs/design-system/component-showcase-consistency-report.md +5 -5
  10. package/docs/design-system/components/README.md +15 -0
  11. package/docs/design-system/components/accordion.md +1 -1
  12. package/docs/design-system/components/activity-feed.md +1 -1
  13. package/docs/design-system/components/activity-heatmap.md +1 -1
  14. package/docs/design-system/components/agent-input.md +85 -0
  15. package/docs/design-system/components/alert-dialog.md +1 -1
  16. package/docs/design-system/components/alert.md +10 -4
  17. package/docs/design-system/components/app-header.md +97 -0
  18. package/docs/design-system/components/approval-card.md +134 -0
  19. package/docs/design-system/components/attribute.md +14 -2
  20. package/docs/design-system/components/avatar.md +1 -1
  21. package/docs/design-system/components/badge.md +1 -1
  22. package/docs/design-system/components/banner.md +1 -1
  23. package/docs/design-system/components/breadcrumbs.md +8 -3
  24. package/docs/design-system/components/button-group.md +1 -1
  25. package/docs/design-system/components/button.md +8 -5
  26. package/docs/design-system/components/card.md +15 -1
  27. package/docs/design-system/components/catalog-components.md +1 -1
  28. package/docs/design-system/components/chart.md +95 -24
  29. package/docs/design-system/components/checkbox.md +1 -1
  30. package/docs/design-system/components/collapsible.md +20 -6
  31. package/docs/design-system/components/command.md +1 -1
  32. package/docs/design-system/components/context-menu.md +1 -1
  33. package/docs/design-system/components/date-picker.md +1 -1
  34. package/docs/design-system/components/file-upload.md +1 -1
  35. package/docs/design-system/components/hover-card.md +1 -1
  36. package/docs/design-system/components/inline-citations.md +93 -0
  37. package/docs/design-system/components/input-group.md +1 -1
  38. package/docs/design-system/components/input.md +59 -3
  39. package/docs/design-system/components/item.md +1 -1
  40. package/docs/design-system/components/kbd.md +6 -4
  41. package/docs/design-system/components/menu.md +35 -4
  42. package/docs/design-system/components/menubar.md +1 -1
  43. package/docs/design-system/components/modal.md +2 -2
  44. package/docs/design-system/components/native-select.md +1 -1
  45. package/docs/design-system/components/navigation-menu.md +1 -1
  46. package/docs/design-system/components/onboarding-step-list-item.md +1 -1
  47. package/docs/design-system/components/page-header.md +58 -17
  48. package/docs/design-system/components/pagination.md +2 -2
  49. package/docs/design-system/components/popover.md +1 -1
  50. package/docs/design-system/components/progress-slider.md +1 -1
  51. package/docs/design-system/components/radio-card.md +1 -1
  52. package/docs/design-system/components/radio-group.md +1 -1
  53. package/docs/design-system/components/resizable.md +1 -1
  54. package/docs/design-system/components/rolling-count.md +61 -0
  55. package/docs/design-system/components/scroll-area.md +1 -1
  56. package/docs/design-system/components/select.md +12 -2
  57. package/docs/design-system/components/sheet.md +1 -1
  58. package/docs/design-system/components/shimmer-text.md +67 -0
  59. package/docs/design-system/components/sidebar.md +75 -8
  60. package/docs/design-system/components/skeleton.md +2 -2
  61. package/docs/design-system/components/slideout.md +1 -1
  62. package/docs/design-system/components/slider.md +2 -2
  63. package/docs/design-system/components/social-button.md +2 -2
  64. package/docs/design-system/components/streaming-text.md +82 -0
  65. package/docs/design-system/components/table.md +103 -21
  66. package/docs/design-system/components/tabs.md +25 -6
  67. package/docs/design-system/components/tag.md +1 -1
  68. package/docs/design-system/components/task-list.md +95 -0
  69. package/docs/design-system/components/textarea.md +1 -1
  70. package/docs/design-system/components/thinking-reasoning.md +72 -0
  71. package/docs/design-system/components/thinking-state.md +67 -0
  72. package/docs/design-system/components/timeline.md +1 -1
  73. package/docs/design-system/components/toast.md +1 -1
  74. package/docs/design-system/components/toggle.md +2 -2
  75. package/docs/design-system/components/toolbar.md +11 -6
  76. package/docs/design-system/components/tooltip.md +6 -4
  77. package/docs/design-system/density-and-elevation.md +16 -16
  78. package/docs/design-system/design-system-test-missing-items.md +8 -8
  79. package/docs/design-system/installation.md +2 -0
  80. package/docs/design-system/tabs.md +2 -1
  81. package/docs/design-system/template-gap-audit.md +32 -0
  82. package/docs/design-system/templates.md +59 -0
  83. package/docs/design-system/token-governance.md +15 -2
  84. package/package.json +2 -2
  85. package/registry/components/accordion.tsx +2 -2
  86. package/registry/components/agent-input-parts.tsx +552 -0
  87. package/registry/components/agent-input-state.ts +156 -0
  88. package/registry/components/agent-input.css +307 -0
  89. package/registry/components/agent-input.tsx +382 -0
  90. package/registry/components/alert-dialog.tsx +2 -2
  91. package/registry/components/alert.tsx +23 -7
  92. package/registry/components/app-header.tsx +151 -0
  93. package/registry/components/approval-card.css +409 -0
  94. package/registry/components/approval-card.tsx +401 -0
  95. package/registry/components/approval-frame.tsx +108 -0
  96. package/registry/components/approval-questions.tsx +559 -0
  97. package/registry/components/attribute.tsx +48 -13
  98. package/registry/components/autocomplete.tsx +15 -68
  99. package/registry/components/avatar.tsx +2 -2
  100. package/registry/components/badge.tsx +8 -7
  101. package/registry/components/button-group.tsx +2 -2
  102. package/registry/components/button.tsx +19 -14
  103. package/registry/components/card.tsx +18 -5
  104. package/registry/components/chart-block-data.ts +177 -0
  105. package/registry/components/chart-block.css +171 -0
  106. package/registry/components/chart-block.tsx +260 -0
  107. package/registry/components/chart-interactions.ts +123 -0
  108. package/registry/components/chart-options.cartesian.ts +162 -0
  109. package/registry/components/chart-options.paint.ts +99 -0
  110. package/registry/components/chart-options.parts.ts +72 -0
  111. package/registry/components/chart-options.radial.ts +109 -0
  112. package/registry/components/chart-options.ts +44 -0
  113. package/registry/components/chart-options.types.ts +67 -0
  114. package/registry/components/chart.tsx +1 -1
  115. package/registry/components/checkbox.tsx +6 -6
  116. package/registry/components/collapsible.tsx +43 -3
  117. package/registry/components/command.tsx +1 -1
  118. package/registry/components/context-menu.tsx +1 -1
  119. package/registry/components/data-chart.tsx +40 -0
  120. package/registry/components/date-picker.tsx +9 -9
  121. package/registry/components/echart-theme.ts +246 -0
  122. package/registry/components/echart.css +49 -0
  123. package/registry/components/echart.tsx +178 -0
  124. package/registry/components/expanded/Breadcrumbs.tsx +5 -1
  125. package/registry/components/expanded/PageHeader.tsx +67 -24
  126. package/registry/components/expanded/Table.tsx +60 -22
  127. package/registry/components/expanded/activityFeed.css +2 -2
  128. package/registry/components/expanded/activityHeatmap.css +1 -1
  129. package/registry/components/expanded/banner.css +2 -2
  130. package/registry/components/expanded/breadcrumbs.css +19 -2
  131. package/registry/components/expanded/catalogComponentsShowcase.css +1 -1
  132. package/registry/components/expanded/fileUpload.css +7 -7
  133. package/registry/components/expanded/onboardingStepListItem.css +2 -2
  134. package/registry/components/expanded/pageHeader.css +38 -44
  135. package/registry/components/expanded/slideout.css +4 -4
  136. package/registry/components/expanded/table.css +58 -9
  137. package/registry/components/expanded/timeline.css +1 -1
  138. package/registry/components/hover-card.tsx +1 -1
  139. package/registry/components/inline-citations.css +126 -0
  140. package/registry/components/inline-citations.tsx +292 -0
  141. package/registry/components/input-group.tsx +4 -4
  142. package/registry/components/input.tsx +150 -137
  143. package/registry/components/item.tsx +1 -1
  144. package/registry/components/kbd.tsx +3 -2
  145. package/registry/components/menu.tsx +117 -12
  146. package/registry/components/menubar.tsx +2 -2
  147. package/registry/components/modal.tsx +3 -3
  148. package/registry/components/native-select.tsx +4 -4
  149. package/registry/components/navigation-menu.tsx +2 -2
  150. package/registry/components/pagination.tsx +4 -4
  151. package/registry/components/popover.tsx +3 -3
  152. package/registry/components/progress-slider.tsx +1 -1
  153. package/registry/components/radio-card.tsx +7 -7
  154. package/registry/components/radio-group.tsx +2 -2
  155. package/registry/components/resizable.tsx +2 -2
  156. package/registry/components/rolling-count.css +37 -0
  157. package/registry/components/rolling-count.tsx +110 -0
  158. package/registry/components/scroll-area.tsx +1 -1
  159. package/registry/components/select.tsx +15 -10
  160. package/registry/components/sheet.tsx +2 -2
  161. package/registry/components/shimmer-text.css +69 -0
  162. package/registry/components/shimmer-text.tsx +43 -0
  163. package/registry/components/sidebar.tsx +528 -223
  164. package/registry/components/skeleton.tsx +1 -1
  165. package/registry/components/slider.tsx +2 -2
  166. package/registry/components/social-button.tsx +1 -1
  167. package/registry/components/streaming-text.css +45 -0
  168. package/registry/components/streaming-text.tsx +165 -0
  169. package/registry/components/table-elements.tsx +164 -5
  170. package/registry/components/tabs.css +32 -4
  171. package/registry/components/tabs.tsx +5 -1
  172. package/registry/components/tag.tsx +1 -1
  173. package/registry/components/task-list.css +328 -0
  174. package/registry/components/task-list.tsx +429 -0
  175. package/registry/components/textarea.tsx +4 -4
  176. package/registry/components/thinking-reasoning.css +178 -0
  177. package/registry/components/thinking-reasoning.tsx +253 -0
  178. package/registry/components/thinking-state.css +8 -0
  179. package/registry/components/thinking-state.tsx +46 -0
  180. package/registry/components/toast.tsx +1 -1
  181. package/registry/components/toggle.tsx +2 -2
  182. package/registry/components/toolbar.tsx +6 -6
  183. package/registry/components/tooltip.tsx +6 -4
  184. package/registry/examples/agent-input-demo.tsx +90 -0
  185. package/registry/examples/app-header-demo.tsx +40 -0
  186. package/registry/examples/approval-card-demo.tsx +83 -0
  187. package/registry/examples/button-demo.tsx +3 -0
  188. package/registry/examples/chart-block-demo.tsx +5 -0
  189. package/registry/examples/chart-demo.tsx +6 -21
  190. package/registry/examples/collection-filter-bar-demo.tsx +1 -1
  191. package/registry/examples/control-density-contract-demo.tsx +5 -1
  192. package/registry/examples/inline-citations-demo.tsx +31 -0
  193. package/registry/examples/input-actions-demo.tsx +36 -0
  194. package/registry/examples/menu-demo.tsx +1 -1
  195. package/registry/examples/popover-demo.tsx +1 -0
  196. package/registry/examples/rolling-count-demo.tsx +39 -0
  197. package/registry/examples/shimmer-text-demo.tsx +20 -0
  198. package/registry/examples/streaming-text-demo.tsx +28 -0
  199. package/registry/examples/task-list-demo.tsx +74 -0
  200. package/registry/examples/thinking-reasoning-demo.tsx +74 -0
  201. package/registry/examples/thinking-state-demo.tsx +13 -0
  202. package/registry/guidance/charts.LICENSE.txt +24 -0
  203. package/registry/hooks/use-controllable-state.ts +33 -0
  204. package/registry/hooks/use-listbox-navigation.ts +73 -0
  205. package/registry/hooks/use-motion-end.ts +55 -0
  206. package/registry/hooks/use-reduced-motion.ts +28 -0
  207. package/registry/index.json +1808 -190
  208. package/registry/styles/globals.css +992 -1088
  209. package/registry.json +385 -10
  210. package/schema/registry.schema.json +5 -1
  211. package/schema/tokens.schema.json +8 -4
  212. package/src/cli/file-transaction.js +15 -8
  213. package/src/cli/index.js +22 -29
  214. package/tokens/banhaten.tokens.json +490 -192
@@ -0,0 +1,292 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ArrowUpRightIcon } from "lucide-react"
5
+
6
+ import { cn } from "@/lib/utils"
7
+ import {
8
+ Tooltip,
9
+ TooltipContent,
10
+ TooltipProvider,
11
+ TooltipTrigger,
12
+ } from "@/components/ui/tooltip"
13
+
14
+ import "./inline-citations.css"
15
+
16
+ type CitationSource = {
17
+ /** Domain shown next to the label in the reference list. */
18
+ host?: string
19
+ label: string
20
+ /** Marker number. Defaults to the position in the list, starting at 1. */
21
+ n?: number
22
+ url: string
23
+ }
24
+
25
+ type InlineCitationsLabels = {
26
+ /** Accessible name for a marker, for example "Citation 1: Attention Is All You Need". */
27
+ citation: (n: number, label: string) => string
28
+ /** Accessible name of the reference list. */
29
+ sources: string
30
+ }
31
+
32
+ const defaultLabels: InlineCitationsLabels = {
33
+ citation: (n, label) => `Citation ${n}: ${label}`,
34
+ sources: "Sources",
35
+ }
36
+
37
+ type ResolvedSource = CitationSource & { n: number }
38
+
39
+ function resolveSources(sources: readonly CitationSource[]): ResolvedSource[] {
40
+ return sources.map((source, index) => ({
41
+ ...source,
42
+ n: source.n ?? index + 1,
43
+ }))
44
+ }
45
+
46
+ /**
47
+ * Citation URLs often come from model output or search results, so only web
48
+ * addresses become links. Anything else, such as a `javascript:` URL that
49
+ * React 18 would still render, counts as no link at all. Relative links
50
+ * resolve against the page, which is always a web address, so they pass.
51
+ */
52
+ function linkableUrl(url: string | undefined) {
53
+ if (!url) return undefined
54
+ try {
55
+ const { protocol } = new URL(url, "https://citation.invalid")
56
+ return protocol === "http:" || protocol === "https:" ? url : undefined
57
+ } catch {
58
+ return undefined
59
+ }
60
+ }
61
+
62
+ type CitationContextValue = {
63
+ labels: InlineCitationsLabels
64
+ sources: readonly ResolvedSource[]
65
+ }
66
+
67
+ /** The sources InlineCitations shares with the marks composed inside it. */
68
+ const CitationContext = React.createContext<CitationContextValue | null>(null)
69
+
70
+ type CitationMarkProps = Omit<React.ComponentProps<"a">, "children"> & {
71
+ /** Reference name revealed in a tooltip. Defaults to the source's label. */
72
+ label?: string
73
+ /** Marker number, matched against the `n` of the InlineCitations sources. */
74
+ n: number
75
+ }
76
+
77
+ /**
78
+ * Superscript numbered chip that links to its source. Inside InlineCitations it
79
+ * finds the source by number; elsewhere pass `href` and `label`. A mark with
80
+ * no web address to link to renders nothing rather than a dead chip.
81
+ */
82
+ const CitationMark = React.forwardRef<HTMLAnchorElement, CitationMarkProps>(
83
+ function CitationMark(
84
+ { "aria-label": ariaLabel, className, href, label, n, ...props },
85
+ ref
86
+ ) {
87
+ const context = React.useContext(CitationContext)
88
+ const source = context?.sources.find((item) => item.n === n)
89
+ const url = linkableUrl(href ?? source?.url)
90
+ const name = label ?? source?.label
91
+ if (!url) return null
92
+
93
+ const labels = context?.labels ?? defaultLabels
94
+ const mark = (
95
+ <a
96
+ aria-label={ariaLabel ?? (name ? labels.citation(n, name) : undefined)}
97
+ data-slot="citation-mark"
98
+ href={url}
99
+ ref={ref}
100
+ rel="noreferrer"
101
+ target="_blank"
102
+ className={cn("no-underline", className)}
103
+ {...props}
104
+ >
105
+ {n}
106
+ </a>
107
+ )
108
+
109
+ if (!name) return mark
110
+
111
+ return (
112
+ <TooltipProvider>
113
+ <Tooltip>
114
+ <TooltipTrigger asChild>{mark}</TooltipTrigger>
115
+ <TooltipContent
116
+ pointerPosition="bottom-center"
117
+ showShortcut={false}
118
+ variant="dark"
119
+ >
120
+ {name}
121
+ </TooltipContent>
122
+ </Tooltip>
123
+ </TooltipProvider>
124
+ )
125
+ }
126
+ )
127
+
128
+ type CitationProseProps = React.ComponentProps<"p">
129
+
130
+ /** Paragraph of cited prose. Place CitationMark where a claim needs support. */
131
+ function CitationProse({ className, ...props }: CitationProseProps) {
132
+ return (
133
+ <p
134
+ data-slot="citation-prose"
135
+ className={cn("m-0 min-w-0", className)}
136
+ {...props}
137
+ />
138
+ )
139
+ }
140
+
141
+ type CitationItemProps = Omit<React.ComponentProps<"a">, "children"> & {
142
+ host?: string
143
+ label: string
144
+ n: number
145
+ }
146
+
147
+ /**
148
+ * One row of the reference list: number, label, host, and an external arrow.
149
+ * Without a web address the row stays readable but is not a link.
150
+ */
151
+ const CitationItem = React.forwardRef<HTMLAnchorElement, CitationItemProps>(
152
+ function CitationItem({ className, host, href, label, n, ...props }, ref) {
153
+ const url = linkableUrl(href)
154
+
155
+ return (
156
+ <a
157
+ data-slot="citation-item"
158
+ href={url}
159
+ ref={ref}
160
+ rel={url ? "noreferrer" : undefined}
161
+ target={url ? "_blank" : undefined}
162
+ className={cn("no-underline", className)}
163
+ {...props}
164
+ >
165
+ <span data-slot="citation-mark">{n}</span>
166
+ <span data-slot="citation-item-label" dir="auto">
167
+ {label}
168
+ </span>
169
+ {host ? (
170
+ <>
171
+ <span aria-hidden="true" data-slot="citation-item-separator">
172
+ ·
173
+ </span>
174
+ <span data-slot="citation-item-host" dir="ltr">
175
+ {host}
176
+ </span>
177
+ </>
178
+ ) : null}
179
+ {url ? (
180
+ <ArrowUpRightIcon
181
+ aria-hidden="true"
182
+ data-slot="citation-item-arrow"
183
+ strokeWidth="var(--bh-icon-stroke-180)"
184
+ />
185
+ ) : null}
186
+ </a>
187
+ )
188
+ }
189
+ )
190
+
191
+ type CitationListProps = React.ComponentProps<"nav"> & {
192
+ sources?: readonly CitationSource[]
193
+ }
194
+
195
+ /** Compact source list rendered under cited prose. */
196
+ function CitationList({
197
+ "aria-label": ariaLabel = defaultLabels.sources,
198
+ children,
199
+ className,
200
+ sources = [],
201
+ ...props
202
+ }: CitationListProps) {
203
+ return (
204
+ <nav
205
+ aria-label={ariaLabel}
206
+ data-slot="citation-list"
207
+ className={cn("min-w-0", className)}
208
+ {...props}
209
+ >
210
+ {resolveSources(sources).map((source) => (
211
+ <CitationItem
212
+ host={source.host}
213
+ href={source.url}
214
+ key={source.n}
215
+ label={source.label}
216
+ n={source.n}
217
+ />
218
+ ))}
219
+ {children}
220
+ </nav>
221
+ )
222
+ }
223
+
224
+ type InlineCitationsProps = Omit<React.ComponentProps<"div">, "children"> & {
225
+ /** Cited prose: CitationProse paragraphs with CitationMark markers. */
226
+ children?: React.ReactNode
227
+ labels?: Partial<InlineCitationsLabels>
228
+ /** Hides the reference list under the prose. */
229
+ showSources?: boolean
230
+ sources: readonly CitationSource[]
231
+ }
232
+
233
+ /**
234
+ * Prose with superscript citation chips plus a compact reference list. Marks
235
+ * inside it link straight to their numbered source and reveal its name on
236
+ * hover.
237
+ */
238
+ const InlineCitations = React.forwardRef<HTMLDivElement, InlineCitationsProps>(
239
+ function InlineCitations(
240
+ {
241
+ children,
242
+ className,
243
+ labels: labelOverrides,
244
+ showSources = true,
245
+ sources,
246
+ ...props
247
+ },
248
+ ref
249
+ ) {
250
+ const context = React.useMemo<CitationContextValue>(
251
+ () => ({
252
+ labels: { ...defaultLabels, ...labelOverrides },
253
+ sources: resolveSources(sources),
254
+ }),
255
+ [labelOverrides, sources]
256
+ )
257
+
258
+ return (
259
+ <CitationContext.Provider value={context}>
260
+ <div
261
+ data-slot="inline-citations"
262
+ ref={ref}
263
+ className={cn("min-w-0 max-w-full", className)}
264
+ {...props}
265
+ >
266
+ {children}
267
+ {/* An empty list would only draw its divider. */}
268
+ {showSources && sources.length > 0 ? (
269
+ <CitationList aria-label={context.labels.sources} sources={sources} />
270
+ ) : null}
271
+ </div>
272
+ </CitationContext.Provider>
273
+ )
274
+ }
275
+ )
276
+
277
+ export {
278
+ CitationItem,
279
+ CitationList,
280
+ CitationMark,
281
+ CitationProse,
282
+ InlineCitations,
283
+ }
284
+ export type {
285
+ CitationItemProps,
286
+ CitationListProps,
287
+ CitationMarkProps,
288
+ CitationProseProps,
289
+ CitationSource,
290
+ InlineCitationsLabels,
291
+ InlineCitationsProps,
292
+ }
@@ -10,9 +10,9 @@ import { cn } from "@/lib/utils"
10
10
  const inputGroupVariants = cva(
11
11
  [
12
12
  "group/input-group relative flex w-[var(--bh-input-width)] max-w-full items-stretch overflow-hidden rounded-[var(--bh-input-radius)]",
13
- "[--bh-input-border:var(--bh-border-input)] [--shadow-input:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-input-border,var(--bh-border-input)),var(--shadow-component-default)]",
14
- "bg-[var(--bh-interactive-input-default)] shadow-[var(--shadow-input)] transition-[background-color,box-shadow]",
15
- "focus-within:shadow-[var(--shadow-input-focus-ring)] data-[disabled=true]:bg-[var(--bh-interactive-input-disabled)] data-[disabled=true]:shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
13
+ "[--bh-input-border:var(--bh-border-input)] [--elevation-input:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-input-border,var(--bh-border-input)),var(--elevation-component-default)]",
14
+ "bg-[var(--bh-interactive-input-default)] shadow-[var(--elevation-input)] transition-[background-color,box-shadow]",
15
+ "focus-within:shadow-[var(--elevation-input-focus-ring)] data-[disabled=true]:bg-[var(--bh-interactive-input-disabled)] data-[disabled=true]:shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
16
16
  ],
17
17
  {
18
18
  variants: {
@@ -23,7 +23,7 @@ const inputGroupVariants = cva(
23
23
  state: {
24
24
  default: "",
25
25
  error:
26
- "[--bh-input-border:var(--bh-border-danger-strong)] focus-within:shadow-[var(--shadow-input)]",
26
+ "[--bh-input-border:var(--bh-border-danger-strong)] focus-within:shadow-[var(--elevation-input)]",
27
27
  },
28
28
  variant: {
29
29
  default: "",