@veevarts/design-system 2.0.0-alpha.57 → 2.0.0-alpha.59
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/README.md +15 -0
- package/dist/components/DatePicker/DatePicker.d.ts +9 -2
- package/dist/components/DatePicker/defaults.d.ts +28 -0
- package/dist/components/DatePicker/index.d.ts +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4629 -4390
- package/dist/patterns/TimeField/TimeField.d.ts +6 -0
- package/dist/patterns/TimeField/index.d.ts +3 -0
- package/dist/patterns/TimeField/time.d.ts +40 -0
- package/dist/patterns/TimeField/types.d.ts +77 -0
- package/dist/patterns/index.d.ts +2 -0
- package/dist/tailwind/index.cjs +82 -4
- package/dist/tailwind/index.d.ts +22 -0
- package/dist/tailwind/index.mjs +79 -4
- package/dist/tokens/assistant-surface.d.ts +66 -0
- package/dist/tokens/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
2
|
+
import { TimeFieldProps } from './types';
|
|
3
|
+
export declare function TimeField({ value: valueProp, defaultValue, onChange, label, 'aria-label': ariaLabel, placeholder, emptyContent, invalidMessage, minTime, minTimeMessage, listStart, listEnd, listStep, locale, isRequired, isDisabled, isInvalid, errorMessage, isClearable, clearLabel, onBlur, size, variant, labelPlacement, className, inputProps, popoverProps, 'data-testid': dataTestId, }: TimeFieldProps): JSX.Element;
|
|
4
|
+
export declare namespace TimeField {
|
|
5
|
+
var displayName: string;
|
|
6
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The time logic behind {@link TimeField}, kept free of React so it can be
|
|
3
|
+
* tested and reused on its own. Every time in and out is 24-hour `"HH:mm"`.
|
|
4
|
+
*/
|
|
5
|
+
/** Minutes since midnight of an `"HH:mm"` time. */
|
|
6
|
+
export declare function toMinutes(time: string): number;
|
|
7
|
+
/**
|
|
8
|
+
* Read typed text as a time: `"HH:mm"`, or `null` when it is not one.
|
|
9
|
+
*
|
|
10
|
+
* Forgiving on purpose: `"7:15 pm"`, `"7:15pm"`, `"715p"`, `"7p"`, `"19:15"`,
|
|
11
|
+
* `"1915"` and `"7"` all work; case, spaces and dots do not matter
|
|
12
|
+
* (`"7:15 P.M."`). Without am/pm, hours 1–6 read as afternoon (no venue opens
|
|
13
|
+
* at 3 AM) and every other hour as 24-hour: `"3"` is 15:00, `"7"` is 07:00,
|
|
14
|
+
* `"19"` is 19:00, `"0"` is midnight.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* parseTimeInput('715p'); // '19:15'
|
|
18
|
+
* parseTimeInput('3'); // '15:00'
|
|
19
|
+
* parseTimeInput('25'); // null
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseTimeInput(input: string): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* The suggested times: `start` to `end` inclusive, every `step` whole
|
|
24
|
+
* minutes. Empty when `step` is under a minute or `end` is before `start`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildTimeOptions(start: string, end: string, step: number): string[];
|
|
27
|
+
/**
|
|
28
|
+
* Whether the list keeps `time` while `query` is typed. It compares against
|
|
29
|
+
* the 12-hour form (`"7:30"`) and the 24-hour forms (`"19:30"`, `"07:30"`), so
|
|
30
|
+
* it does not depend on how the label is formatted: `"7"` keeps 7:00 and
|
|
31
|
+
* 7:30 AM and PM, `"7p"` only the PM ones, `"19"` the 7 PM ones, `"p"` every
|
|
32
|
+
* PM time.
|
|
33
|
+
*/
|
|
34
|
+
export declare function matchesTimeQuery(time: string, query: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The label for a time in `locale`: `"7:15 PM"` in `en-US`, `"19:15"` in
|
|
37
|
+
* `en-GB`, `"7:15 p. m."` in `es-CO`. No-break spaces become plain ones, so
|
|
38
|
+
* the label matches what people type and what tests search for.
|
|
39
|
+
*/
|
|
40
|
+
export declare function formatTimeLabel(time: string, locale: string): string;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { FocusEvent, ReactNode } from 'react';
|
|
2
|
+
import { AutocompleteProps } from '../../components';
|
|
3
|
+
/** One row of the list: the `"HH:mm"` key and its locale label. */
|
|
4
|
+
export interface TimeFieldOption {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TimeFieldProps {
|
|
9
|
+
/**
|
|
10
|
+
* The time as 24-hour `"HH:mm"` text, or `null` for none. Omit for
|
|
11
|
+
* uncontrolled mode.
|
|
12
|
+
*/
|
|
13
|
+
value?: string | null;
|
|
14
|
+
/** Starting time in uncontrolled mode. */
|
|
15
|
+
defaultValue?: string | null;
|
|
16
|
+
/** Called with the committed `"HH:mm"`, or `null` when a clearable field is emptied. */
|
|
17
|
+
onChange?: (time: string | null) => void;
|
|
18
|
+
/** Visible label. Without one, pass `aria-label`. */
|
|
19
|
+
label?: ReactNode;
|
|
20
|
+
'aria-label'?: string;
|
|
21
|
+
/** "e.g. 7:15 PM". */
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Shown in the list when nothing matches the typed text, or the text was
|
|
25
|
+
* erased ("Type a time like 7:15 PM"). Required and non-empty: HeroUI's
|
|
26
|
+
* own is English, and an Autocomplete that hides an empty list loses its
|
|
27
|
+
* options to `aria-hidden` when they come back.
|
|
28
|
+
*/
|
|
29
|
+
emptyContent: ReactNode;
|
|
30
|
+
/** Shown when the typed text is not a time ("Enter a time like 7:15 PM."). */
|
|
31
|
+
invalidMessage: ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* Earliest allowed `"HH:mm"`. Earlier times leave the list, and typing
|
|
34
|
+
* one, or receiving one as `value`, shows `minTimeMessage`.
|
|
35
|
+
*/
|
|
36
|
+
minTime?: string;
|
|
37
|
+
/** Shown for a time before `minTime` ("Ends after it starts."). Defaults to `invalidMessage`. */
|
|
38
|
+
minTimeMessage?: ReactNode;
|
|
39
|
+
/** First time the list suggests. @default '07:00' */
|
|
40
|
+
listStart?: string;
|
|
41
|
+
/** Last time the list suggests, inclusive. @default '21:00' */
|
|
42
|
+
listEnd?: string;
|
|
43
|
+
/** Minutes between suggested times. @default 30 */
|
|
44
|
+
listStep?: number;
|
|
45
|
+
/**
|
|
46
|
+
* BCP 47 locale the times are written in: "7:15 PM" in `en-US`, "19:15"
|
|
47
|
+
* in `en-GB`. Pass the same one as `HeroUIProvider`. @default 'en-US'
|
|
48
|
+
*/
|
|
49
|
+
locale?: string;
|
|
50
|
+
isRequired?: boolean;
|
|
51
|
+
isDisabled?: boolean;
|
|
52
|
+
/** Marks the field invalid from outside; `errorMessage` is shown with it. */
|
|
53
|
+
isInvalid?: boolean;
|
|
54
|
+
errorMessage?: ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* Whether the field may be emptied: a clear button shows, and leaving it
|
|
57
|
+
* empty commits `null`. Otherwise leaving it empty restores the time it
|
|
58
|
+
* had. @default false
|
|
59
|
+
*/
|
|
60
|
+
isClearable?: boolean;
|
|
61
|
+
/** Accessible name of the clear button ("Clear time"); HeroUI gives it none. */
|
|
62
|
+
clearLabel?: string;
|
|
63
|
+
/** Called after the field has committed what was typed (react-hook-form's `field.onBlur`). */
|
|
64
|
+
onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
|
|
65
|
+
size?: AutocompleteProps['size'];
|
|
66
|
+
/** @default 'bordered' */
|
|
67
|
+
variant?: AutocompleteProps['variant'];
|
|
68
|
+
/** @default 'outside-top' */
|
|
69
|
+
labelPlacement?: AutocompleteProps['labelPlacement'];
|
|
70
|
+
className?: string;
|
|
71
|
+
/** Passed to HeroUI's input: `{ classNames: { inputWrapper: 'h-11' } }`. */
|
|
72
|
+
inputProps?: AutocompleteProps['inputProps'];
|
|
73
|
+
/** Passed to HeroUI's popover. */
|
|
74
|
+
popoverProps?: AutocompleteProps['popoverProps'];
|
|
75
|
+
/** Lands on the `<input>`. Options get `${data-testid}-option-${HH:mm}`. */
|
|
76
|
+
'data-testid'?: string;
|
|
77
|
+
}
|
package/dist/patterns/index.d.ts
CHANGED
|
@@ -71,6 +71,8 @@ export { UnderlineTabs } from './UnderlineTabs';
|
|
|
71
71
|
export type { UnderlineTabsProps, UnderlineTabItem, UnderlineTabsSize, UnderlineTabsLevel } from './UnderlineTabs';
|
|
72
72
|
export { AdminFieldLabel, AdminTextField, adminFieldErrorClass, adminFieldHelpButtonClass, adminFieldHelpContentClass, adminFieldHelpIconClass, adminFieldHintClass, adminFieldLabelClass, adminFieldLabelNoAutoMarkClass, adminFieldLabelRowClass, adminFieldLabelSuffixClass, adminFieldRequiredClass, adminInputClass, adminInputReadOnlyClass, adminInputWrapperClass, } from './AdminTextField';
|
|
73
73
|
export type { AdminTextFieldProps, AdminFieldLabelProps, AdminFieldRequiredProps, AdminFieldHelpProps, } from './AdminTextField';
|
|
74
|
+
export { TimeField, parseTimeInput } from './TimeField';
|
|
75
|
+
export type { TimeFieldProps } from './TimeField';
|
|
74
76
|
export { RowActions } from './RowActions';
|
|
75
77
|
export type { RowActionsProps, RowAction } from './RowActions';
|
|
76
78
|
export { PickerRow } from './PickerRow';
|
package/dist/tailwind/index.cjs
CHANGED
|
@@ -23,6 +23,9 @@ __export(index_exports, {
|
|
|
23
23
|
adminSurfaceCss: () => adminSurfaceCss,
|
|
24
24
|
adminSurfaceTailwindColors: () => adminSurfaceTailwindColors,
|
|
25
25
|
adminSurfaceTokens: () => adminSurfaceTokens,
|
|
26
|
+
assistantSurfacePlugin: () => assistantSurfacePlugin,
|
|
27
|
+
assistantSurfaceTailwindColors: () => assistantSurfaceTailwindColors,
|
|
28
|
+
assistantSurfaceTokens: () => assistantSurfaceTokens,
|
|
26
29
|
colors: () => colors,
|
|
27
30
|
createHeroUIConfig: () => createHeroUIConfig,
|
|
28
31
|
deepMerge: () => deepMerge,
|
|
@@ -258,12 +261,12 @@ function adminSurfaceCss({
|
|
|
258
261
|
scope = ".acct",
|
|
259
262
|
fontFamily = "'NeueMontreal', system-ui, sans-serif"
|
|
260
263
|
} = {}) {
|
|
261
|
-
const
|
|
264
|
+
const declarations2 = Object.entries(adminSurfaceTokens).map(([name, value]) => ` ${name}: ${value};`).join("\n");
|
|
262
265
|
const typography2 = fontFamily ? `
|
|
263
266
|
font-family: ${fontFamily};
|
|
264
267
|
color: var(--ink);` : "";
|
|
265
268
|
return `${scope} {
|
|
266
|
-
${
|
|
269
|
+
${declarations2}${typography2}
|
|
267
270
|
}
|
|
268
271
|
`;
|
|
269
272
|
}
|
|
@@ -308,6 +311,70 @@ var posSurfaceTokens = {
|
|
|
308
311
|
};
|
|
309
312
|
var posSurfaceTailwindColors = { ...posSurfaceTokens };
|
|
310
313
|
|
|
314
|
+
// src/tokens/assistant-surface.ts
|
|
315
|
+
var info = colors.palettes.info;
|
|
316
|
+
var HEROUI_CONTENT = {
|
|
317
|
+
light: { content1: "#ffffff", content2: "#f4f4f5" },
|
|
318
|
+
dark: { content1: "#18181b", content2: "#27272a" }
|
|
319
|
+
};
|
|
320
|
+
var ASSISTANT_SURFACE_TOKEN_NAMES = [
|
|
321
|
+
/** Text and icon tone that marks something as the assistant's. */
|
|
322
|
+
"accent",
|
|
323
|
+
/** Tint behind small assistant marks (an avatar disc, an info notice). */
|
|
324
|
+
"fill",
|
|
325
|
+
/** Hairline around assistant regions. */
|
|
326
|
+
"border",
|
|
327
|
+
/** Fill of the person's own turn. */
|
|
328
|
+
"user-bubble",
|
|
329
|
+
/** Fill of the assistant's turn, where an app draws it as a bubble. */
|
|
330
|
+
"assistant-bubble",
|
|
331
|
+
/** Focus ring inside assistant surfaces. */
|
|
332
|
+
"focus"
|
|
333
|
+
];
|
|
334
|
+
var assistantSurfaceTokens = {
|
|
335
|
+
light: {
|
|
336
|
+
accent: info[600],
|
|
337
|
+
fill: info[100],
|
|
338
|
+
border: info[200],
|
|
339
|
+
"user-bubble": HEROUI_CONTENT.light.content2,
|
|
340
|
+
"assistant-bubble": HEROUI_CONTENT.light.content1,
|
|
341
|
+
focus: info[500]
|
|
342
|
+
},
|
|
343
|
+
dark: {
|
|
344
|
+
accent: info[300],
|
|
345
|
+
fill: info[900],
|
|
346
|
+
border: info[800],
|
|
347
|
+
"user-bubble": HEROUI_CONTENT.dark.content2,
|
|
348
|
+
"assistant-bubble": HEROUI_CONTENT.dark.content1,
|
|
349
|
+
focus: info[400]
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
function hexToChannels(hex) {
|
|
353
|
+
if (!/^#[0-9a-f]{6}$/i.test(hex)) throw new Error(`bad hex: ${hex}`);
|
|
354
|
+
return [1, 3, 5].map((start) => parseInt(hex.slice(start, start + 2), 16)).join(" ");
|
|
355
|
+
}
|
|
356
|
+
var assistantSurfaceVar = (name) => `--ai-${name}`;
|
|
357
|
+
var declarations = (theme) => Object.fromEntries(
|
|
358
|
+
ASSISTANT_SURFACE_TOKEN_NAMES.map((name) => [
|
|
359
|
+
assistantSurfaceVar(name),
|
|
360
|
+
hexToChannels(assistantSurfaceTokens[theme][name])
|
|
361
|
+
])
|
|
362
|
+
);
|
|
363
|
+
var ASSISTANT_SURFACE_SELECTORS = {
|
|
364
|
+
light: ':root, .light, [data-theme="light"]',
|
|
365
|
+
dark: ".dark"
|
|
366
|
+
};
|
|
367
|
+
var assistantSurfaceBase = {
|
|
368
|
+
[ASSISTANT_SURFACE_SELECTORS.light]: declarations("light"),
|
|
369
|
+
[ASSISTANT_SURFACE_SELECTORS.dark]: declarations("dark")
|
|
370
|
+
};
|
|
371
|
+
var assistantSurfaceTailwindColors = Object.fromEntries(
|
|
372
|
+
ASSISTANT_SURFACE_TOKEN_NAMES.map((name) => [
|
|
373
|
+
name,
|
|
374
|
+
`rgb(var(${assistantSurfaceVar(name)}, ${hexToChannels(assistantSurfaceTokens.light[name])}) / <alpha-value>)`
|
|
375
|
+
])
|
|
376
|
+
);
|
|
377
|
+
|
|
311
378
|
// src/tailwind/index.ts
|
|
312
379
|
var tailwindTheme = {
|
|
313
380
|
colors: {
|
|
@@ -323,7 +390,11 @@ var tailwindTheme = {
|
|
|
323
390
|
// `danger`/`info`/`warn` do not shadow the semantic palettes, and fed
|
|
324
391
|
// from the token object so utility and token cannot disagree.
|
|
325
392
|
// See src/tokens/pos-surface.ts.
|
|
326
|
-
pos: posSurfaceTailwindColors
|
|
393
|
+
pos: posSurfaceTailwindColors,
|
|
394
|
+
// Assistant palette. Unlike `acct`/`pos` these resolve to CSS custom
|
|
395
|
+
// properties, because they have a dark value: the preset's plugin
|
|
396
|
+
// below writes the properties. See src/tokens/assistant-surface.ts.
|
|
397
|
+
ai: assistantSurfaceTailwindColors
|
|
327
398
|
},
|
|
328
399
|
fontFamily: typography.fontFamily,
|
|
329
400
|
spacing,
|
|
@@ -402,11 +473,15 @@ var veevartContent = [
|
|
|
402
473
|
"./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
|
|
403
474
|
"./node_modules/@veevarts/design-system/dist/**/*.{js,mjs,jsx,tsx}"
|
|
404
475
|
];
|
|
476
|
+
function assistantSurfacePlugin({ addBase }) {
|
|
477
|
+
addBase(assistantSurfaceBase);
|
|
478
|
+
}
|
|
405
479
|
var veevartPreset = {
|
|
406
480
|
theme: {
|
|
407
481
|
extend: tailwindTheme
|
|
408
482
|
},
|
|
409
|
-
darkMode: "class"
|
|
483
|
+
darkMode: "class",
|
|
484
|
+
plugins: [assistantSurfacePlugin]
|
|
410
485
|
};
|
|
411
486
|
var tokens = {
|
|
412
487
|
colors,
|
|
@@ -419,6 +494,9 @@ var tokens = {
|
|
|
419
494
|
adminSurfaceCss,
|
|
420
495
|
adminSurfaceTailwindColors,
|
|
421
496
|
adminSurfaceTokens,
|
|
497
|
+
assistantSurfacePlugin,
|
|
498
|
+
assistantSurfaceTailwindColors,
|
|
499
|
+
assistantSurfaceTokens,
|
|
422
500
|
colors,
|
|
423
501
|
createHeroUIConfig,
|
|
424
502
|
deepMerge,
|
package/dist/tailwind/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { typography } from '../tokens/typography';
|
|
|
3
3
|
import { spacing } from '../tokens/spacing';
|
|
4
4
|
export { colors, typography, spacing };
|
|
5
5
|
export { adminSurfaceCss, adminSurfaceTokens, adminSurfaceTailwindColors } from '../tokens/admin-surface';
|
|
6
|
+
export { assistantSurfaceTokens, assistantSurfaceTailwindColors } from '../tokens/assistant-surface';
|
|
6
7
|
export interface ColorPalette {
|
|
7
8
|
50: string;
|
|
8
9
|
100: string;
|
|
@@ -48,6 +49,7 @@ export declare const tailwindTheme: {
|
|
|
48
49
|
colors: {
|
|
49
50
|
acct: Record<string, string>;
|
|
50
51
|
pos: Record<string, string>;
|
|
52
|
+
ai: Record<"accent" | "fill" | "border" | "user-bubble" | "assistant-bubble" | "focus", string>;
|
|
51
53
|
secondary: "#000000";
|
|
52
54
|
success: "#057A54";
|
|
53
55
|
warning: "#F5A524";
|
|
@@ -251,11 +253,28 @@ export declare function createHeroUIConfig(overrides?: HeroUIConfigOverrides): H
|
|
|
251
253
|
* Includes HeroUI theme and Design System components
|
|
252
254
|
*/
|
|
253
255
|
export declare const veevartContent: string[];
|
|
256
|
+
/** The slice of Tailwind's plugin API the preset's plugins use. */
|
|
257
|
+
export interface PresetPluginApi {
|
|
258
|
+
addBase: (base: Record<string, Record<string, string>>) => void;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Writes the `--ai-*` custom properties: light values on `:root`, dark values
|
|
262
|
+
* under `.dark`. The `ai-*` colours read them, so without this plugin they
|
|
263
|
+
* stay on their light fallbacks.
|
|
264
|
+
*
|
|
265
|
+
* A plain function, not `tailwindcss/plugin`, so this bundle does not pull
|
|
266
|
+
* Tailwind in. Add it to `plugins` yourself only if you extend
|
|
267
|
+
* `tokens.tailwindTheme` instead of using `veevartPreset`.
|
|
268
|
+
*/
|
|
269
|
+
export declare function assistantSurfacePlugin({ addBase }: PresetPluginApi): void;
|
|
254
270
|
/**
|
|
255
271
|
* Veevart Design System Tailwind preset
|
|
256
272
|
*
|
|
257
273
|
* Use this preset in your tailwind.config.js to get all Veevart tokens
|
|
258
274
|
* and styling defaults. Use veevartContent in your content array.
|
|
275
|
+
*
|
|
276
|
+
* Tailwind runs a preset's plugins alongside the app's own (HeroUI's, for
|
|
277
|
+
* instance), so the app keeps declaring `plugins` as before.
|
|
259
278
|
*/
|
|
260
279
|
export declare const veevartPreset: {
|
|
261
280
|
theme: {
|
|
@@ -263,6 +282,7 @@ export declare const veevartPreset: {
|
|
|
263
282
|
colors: {
|
|
264
283
|
acct: Record<string, string>;
|
|
265
284
|
pos: Record<string, string>;
|
|
285
|
+
ai: Record<"accent" | "fill" | "border" | "user-bubble" | "assistant-bubble" | "focus", string>;
|
|
266
286
|
secondary: "#000000";
|
|
267
287
|
success: "#057A54";
|
|
268
288
|
warning: "#F5A524";
|
|
@@ -351,6 +371,7 @@ export declare const veevartPreset: {
|
|
|
351
371
|
};
|
|
352
372
|
};
|
|
353
373
|
darkMode: "class";
|
|
374
|
+
plugins: (typeof assistantSurfacePlugin)[];
|
|
354
375
|
};
|
|
355
376
|
/**
|
|
356
377
|
* All tokens bundled together for convenience
|
|
@@ -508,6 +529,7 @@ export declare const tokens: {
|
|
|
508
529
|
colors: {
|
|
509
530
|
acct: Record<string, string>;
|
|
510
531
|
pos: Record<string, string>;
|
|
532
|
+
ai: Record<"accent" | "fill" | "border" | "user-bubble" | "assistant-bubble" | "focus", string>;
|
|
511
533
|
secondary: "#000000";
|
|
512
534
|
success: "#057A54";
|
|
513
535
|
warning: "#F5A524";
|
package/dist/tailwind/index.mjs
CHANGED
|
@@ -219,12 +219,12 @@ function adminSurfaceCss({
|
|
|
219
219
|
scope = ".acct",
|
|
220
220
|
fontFamily = "'NeueMontreal', system-ui, sans-serif"
|
|
221
221
|
} = {}) {
|
|
222
|
-
const
|
|
222
|
+
const declarations2 = Object.entries(adminSurfaceTokens).map(([name, value]) => ` ${name}: ${value};`).join("\n");
|
|
223
223
|
const typography2 = fontFamily ? `
|
|
224
224
|
font-family: ${fontFamily};
|
|
225
225
|
color: var(--ink);` : "";
|
|
226
226
|
return `${scope} {
|
|
227
|
-
${
|
|
227
|
+
${declarations2}${typography2}
|
|
228
228
|
}
|
|
229
229
|
`;
|
|
230
230
|
}
|
|
@@ -269,6 +269,70 @@ var posSurfaceTokens = {
|
|
|
269
269
|
};
|
|
270
270
|
var posSurfaceTailwindColors = { ...posSurfaceTokens };
|
|
271
271
|
|
|
272
|
+
// src/tokens/assistant-surface.ts
|
|
273
|
+
var info = colors.palettes.info;
|
|
274
|
+
var HEROUI_CONTENT = {
|
|
275
|
+
light: { content1: "#ffffff", content2: "#f4f4f5" },
|
|
276
|
+
dark: { content1: "#18181b", content2: "#27272a" }
|
|
277
|
+
};
|
|
278
|
+
var ASSISTANT_SURFACE_TOKEN_NAMES = [
|
|
279
|
+
/** Text and icon tone that marks something as the assistant's. */
|
|
280
|
+
"accent",
|
|
281
|
+
/** Tint behind small assistant marks (an avatar disc, an info notice). */
|
|
282
|
+
"fill",
|
|
283
|
+
/** Hairline around assistant regions. */
|
|
284
|
+
"border",
|
|
285
|
+
/** Fill of the person's own turn. */
|
|
286
|
+
"user-bubble",
|
|
287
|
+
/** Fill of the assistant's turn, where an app draws it as a bubble. */
|
|
288
|
+
"assistant-bubble",
|
|
289
|
+
/** Focus ring inside assistant surfaces. */
|
|
290
|
+
"focus"
|
|
291
|
+
];
|
|
292
|
+
var assistantSurfaceTokens = {
|
|
293
|
+
light: {
|
|
294
|
+
accent: info[600],
|
|
295
|
+
fill: info[100],
|
|
296
|
+
border: info[200],
|
|
297
|
+
"user-bubble": HEROUI_CONTENT.light.content2,
|
|
298
|
+
"assistant-bubble": HEROUI_CONTENT.light.content1,
|
|
299
|
+
focus: info[500]
|
|
300
|
+
},
|
|
301
|
+
dark: {
|
|
302
|
+
accent: info[300],
|
|
303
|
+
fill: info[900],
|
|
304
|
+
border: info[800],
|
|
305
|
+
"user-bubble": HEROUI_CONTENT.dark.content2,
|
|
306
|
+
"assistant-bubble": HEROUI_CONTENT.dark.content1,
|
|
307
|
+
focus: info[400]
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
function hexToChannels(hex) {
|
|
311
|
+
if (!/^#[0-9a-f]{6}$/i.test(hex)) throw new Error(`bad hex: ${hex}`);
|
|
312
|
+
return [1, 3, 5].map((start) => parseInt(hex.slice(start, start + 2), 16)).join(" ");
|
|
313
|
+
}
|
|
314
|
+
var assistantSurfaceVar = (name) => `--ai-${name}`;
|
|
315
|
+
var declarations = (theme) => Object.fromEntries(
|
|
316
|
+
ASSISTANT_SURFACE_TOKEN_NAMES.map((name) => [
|
|
317
|
+
assistantSurfaceVar(name),
|
|
318
|
+
hexToChannels(assistantSurfaceTokens[theme][name])
|
|
319
|
+
])
|
|
320
|
+
);
|
|
321
|
+
var ASSISTANT_SURFACE_SELECTORS = {
|
|
322
|
+
light: ':root, .light, [data-theme="light"]',
|
|
323
|
+
dark: ".dark"
|
|
324
|
+
};
|
|
325
|
+
var assistantSurfaceBase = {
|
|
326
|
+
[ASSISTANT_SURFACE_SELECTORS.light]: declarations("light"),
|
|
327
|
+
[ASSISTANT_SURFACE_SELECTORS.dark]: declarations("dark")
|
|
328
|
+
};
|
|
329
|
+
var assistantSurfaceTailwindColors = Object.fromEntries(
|
|
330
|
+
ASSISTANT_SURFACE_TOKEN_NAMES.map((name) => [
|
|
331
|
+
name,
|
|
332
|
+
`rgb(var(${assistantSurfaceVar(name)}, ${hexToChannels(assistantSurfaceTokens.light[name])}) / <alpha-value>)`
|
|
333
|
+
])
|
|
334
|
+
);
|
|
335
|
+
|
|
272
336
|
// src/tailwind/index.ts
|
|
273
337
|
var tailwindTheme = {
|
|
274
338
|
colors: {
|
|
@@ -284,7 +348,11 @@ var tailwindTheme = {
|
|
|
284
348
|
// `danger`/`info`/`warn` do not shadow the semantic palettes, and fed
|
|
285
349
|
// from the token object so utility and token cannot disagree.
|
|
286
350
|
// See src/tokens/pos-surface.ts.
|
|
287
|
-
pos: posSurfaceTailwindColors
|
|
351
|
+
pos: posSurfaceTailwindColors,
|
|
352
|
+
// Assistant palette. Unlike `acct`/`pos` these resolve to CSS custom
|
|
353
|
+
// properties, because they have a dark value: the preset's plugin
|
|
354
|
+
// below writes the properties. See src/tokens/assistant-surface.ts.
|
|
355
|
+
ai: assistantSurfaceTailwindColors
|
|
288
356
|
},
|
|
289
357
|
fontFamily: typography.fontFamily,
|
|
290
358
|
spacing,
|
|
@@ -363,11 +431,15 @@ var veevartContent = [
|
|
|
363
431
|
"./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
|
|
364
432
|
"./node_modules/@veevarts/design-system/dist/**/*.{js,mjs,jsx,tsx}"
|
|
365
433
|
];
|
|
434
|
+
function assistantSurfacePlugin({ addBase }) {
|
|
435
|
+
addBase(assistantSurfaceBase);
|
|
436
|
+
}
|
|
366
437
|
var veevartPreset = {
|
|
367
438
|
theme: {
|
|
368
439
|
extend: tailwindTheme
|
|
369
440
|
},
|
|
370
|
-
darkMode: "class"
|
|
441
|
+
darkMode: "class",
|
|
442
|
+
plugins: [assistantSurfacePlugin]
|
|
371
443
|
};
|
|
372
444
|
var tokens = {
|
|
373
445
|
colors,
|
|
@@ -379,6 +451,9 @@ export {
|
|
|
379
451
|
adminSurfaceCss,
|
|
380
452
|
adminSurfaceTailwindColors,
|
|
381
453
|
adminSurfaceTokens,
|
|
454
|
+
assistantSurfacePlugin,
|
|
455
|
+
assistantSurfaceTailwindColors,
|
|
456
|
+
assistantSurfaceTokens,
|
|
382
457
|
colors,
|
|
383
458
|
createHeroUIConfig,
|
|
384
459
|
deepMerge,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The assistant ("AI") palette: the one place an assistant surface takes its
|
|
3
|
+
* accent, tints and focus ring from, in light AND dark (INI-0581).
|
|
4
|
+
*
|
|
5
|
+
* PLACEHOLDER HUE. Design has not picked the assistant colour yet. These
|
|
6
|
+
* values are the `info` blue scale, the only hue in the DS that no product
|
|
7
|
+
* already uses for something else, and they ship so the assistant pieces can
|
|
8
|
+
* be built and measured now. When Design signs a hue off, change the two maps
|
|
9
|
+
* below and nothing else: every `ai-*` utility, the CSS custom properties and
|
|
10
|
+
* the contrast tests all read from here. The two bubbles are neutrals on
|
|
11
|
+
* purpose (only the assistant carries the hue); Design may retune them too.
|
|
12
|
+
*
|
|
13
|
+
* WHY IT CARRIES ITS OWN DARK VALUES. The DS has no dark theme:
|
|
14
|
+
* `createHeroUIConfig` builds `themes.light` only. HeroUI's semantic colours
|
|
15
|
+
* (`content1`, `foreground`, `default-*`, `divider`) still flip under `.dark`,
|
|
16
|
+
* so the assistant pieces style with those plus this palette, and this
|
|
17
|
+
* palette flips with them. A full DS dark theme is a separate, larger piece
|
|
18
|
+
* of work.
|
|
19
|
+
*
|
|
20
|
+
* HOW IT REACHES THE PAGE. The preset adds a plugin that writes each token as
|
|
21
|
+
* a custom property and maps `ai-*` colours to those properties. **The class
|
|
22
|
+
* is the switch:** dark values under `.dark`, light values on `:root`,
|
|
23
|
+
* `.light` and `[data-theme="light"]`. Those are the selectors every HeroUI
|
|
24
|
+
* 2.x in the DS peer range writes its own variables under, so the palette and
|
|
25
|
+
* HeroUI's colours flip together; `src/tailwind/__test__/assistant-heroui-parity.test.ts`
|
|
26
|
+
* holds that against the installed HeroUI. `[data-theme="dark"]` is NOT a
|
|
27
|
+
* switch: HeroUI 2.8 no longer writes dark variables there (2.7 still did),
|
|
28
|
+
* so honouring it would turn `ai-*` dark on white HeroUI cards. An app that
|
|
29
|
+
* puts `.dark` on a subtree gets dark values on that subtree only.
|
|
30
|
+
*
|
|
31
|
+
* Kept apart from `adminSurfaceTokens` on purpose: consumers test that they
|
|
32
|
+
* override every admin token, and a new key there would break them.
|
|
33
|
+
*/
|
|
34
|
+
/** The token names, in the order the docs list them. */
|
|
35
|
+
export declare const ASSISTANT_SURFACE_TOKEN_NAMES: readonly ["accent", "fill", "border", "user-bubble", "assistant-bubble", "focus"];
|
|
36
|
+
export type AssistantSurfaceTokenName = (typeof ASSISTANT_SURFACE_TOKEN_NAMES)[number];
|
|
37
|
+
export type AssistantSurfaceTheme = 'light' | 'dark';
|
|
38
|
+
/** Token name → hex, per theme. Exported so tests and tooling can assert on it directly. */
|
|
39
|
+
export declare const assistantSurfaceTokens: Record<AssistantSurfaceTheme, Record<AssistantSurfaceTokenName, string>>;
|
|
40
|
+
/**
|
|
41
|
+
* `#1d4ed8` → `29 78 216`: the channel form Tailwind's `<alpha-value>` needs.
|
|
42
|
+
* Throws on anything but `#rrggbb`, so a typo in a hue change fails the tests
|
|
43
|
+
* instead of shipping a colour that resolves to nothing.
|
|
44
|
+
*/
|
|
45
|
+
export declare function hexToChannels(hex: string): string;
|
|
46
|
+
/** The custom property behind a token: `accent` → `--ai-accent`. */
|
|
47
|
+
export declare const assistantSurfaceVar: (name: AssistantSurfaceTokenName) => string;
|
|
48
|
+
/**
|
|
49
|
+
* Where each theme's values are written: the selectors every HeroUI 2.x in
|
|
50
|
+
* the peer range writes its own light and dark variables under (see the module
|
|
51
|
+
* comment for why `[data-theme="dark"]` is left out). A `.light` island inside
|
|
52
|
+
* a `.dark` page flips back for both palettes at once.
|
|
53
|
+
*/
|
|
54
|
+
export declare const ASSISTANT_SURFACE_SELECTORS: Record<AssistantSurfaceTheme, string>;
|
|
55
|
+
/** The custom properties as a CSS-in-JS rule set, ready for Tailwind's `addBase`. */
|
|
56
|
+
export declare const assistantSurfaceBase: Record<string, Record<string, string>>;
|
|
57
|
+
/**
|
|
58
|
+
* The palette as Tailwind colours, namespaced under `ai`: `text-ai-accent`,
|
|
59
|
+
* `bg-ai-user-bubble`, `ring-ai-focus`, with opacity modifiers working.
|
|
60
|
+
*
|
|
61
|
+
* Each colour falls back to its LIGHT value when the property is missing, so
|
|
62
|
+
* an app that extends `tokens.tailwindTheme` without the preset's plugin still
|
|
63
|
+
* gets a readable light palette instead of colours that resolve to nothing.
|
|
64
|
+
* Dark values need the plugin.
|
|
65
|
+
*/
|
|
66
|
+
export declare const assistantSurfaceTailwindColors: Record<AssistantSurfaceTokenName, string>;
|
package/dist/tokens/index.d.ts
CHANGED
|
@@ -3,5 +3,7 @@ export { spacing } from './spacing';
|
|
|
3
3
|
export { typography } from './typography';
|
|
4
4
|
export { adminSurfaceCss, adminSurfaceTokens } from './admin-surface';
|
|
5
5
|
export { posSurfaceTokens, posSurfaceTailwindColors } from './pos-surface';
|
|
6
|
+
export { assistantSurfaceTokens } from './assistant-surface';
|
|
6
7
|
export type { ColorToken } from './colors';
|
|
7
8
|
export type { AdminSurfaceCssOptions } from './admin-surface';
|
|
9
|
+
export type { AssistantSurfaceTheme, AssistantSurfaceTokenName } from './assistant-surface';
|