lucent-ui 0.12.0 → 0.13.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.
@@ -1,6 +1,7 @@
1
1
  // Atoms
2
2
  import { COMPONENT_MANIFEST as Avatar } from '../src/components/atoms/Avatar/Avatar.manifest.js';
3
3
  import { COMPONENT_MANIFEST as Badge } from '../src/components/atoms/Badge/Badge.manifest.js';
4
+ import { COMPONENT_MANIFEST as Chip } from '../src/components/atoms/Chip/Chip.manifest.js';
4
5
  import { COMPONENT_MANIFEST as Button } from '../src/components/atoms/Button/Button.manifest.js';
5
6
  import { COMPONENT_MANIFEST as Checkbox } from '../src/components/atoms/Checkbox/Checkbox.manifest.js';
6
7
  import { COMPONENT_MANIFEST as Divider } from '../src/components/atoms/Divider/Divider.manifest.js';
@@ -25,6 +26,7 @@ export const ALL_MANIFESTS = [
25
26
  // Atoms
26
27
  Avatar,
27
28
  Badge,
29
+ Chip,
28
30
  Button,
29
31
  Checkbox,
30
32
  Divider,
@@ -9,7 +9,12 @@ export const COMPONENT_MANIFEST = {
9
9
  'Use a Checkbox for settings that take effect immediately (e.g. "Remember me") or for ' +
10
10
  'selecting multiple items from a list. When only one option may be active at a time, use ' +
11
11
  'Radio instead. The indeterminate state communicates a "select all" parent whose children ' +
12
- 'are partially checked — never use it for a third logical state.',
12
+ 'are partially checked — never use it for a third logical state. ' +
13
+ 'Use the contained variant when you want to add visual emphasis to individual options — ' +
14
+ 'for example, plan selection cards, feature toggles, or consent checkboxes. Contained is ' +
15
+ 'especially useful when checkboxes are standalone or unrelated to each other, since the ' +
16
+ 'border gives each option its own visual weight. Pair with helperText to provide additional ' +
17
+ 'context without cluttering the label.',
13
18
  props: [
14
19
  {
15
20
  name: 'checked',
@@ -55,8 +60,21 @@ export const COMPONENT_MANIFEST = {
55
60
  type: 'enum',
56
61
  required: false,
57
62
  default: 'md',
58
- description: 'Size of the checkbox box.',
59
- enumValues: ['sm', 'md'],
63
+ description: 'Size of the checkbox box and label text.',
64
+ enumValues: ['sm', 'md', 'lg'],
65
+ },
66
+ {
67
+ name: 'contained',
68
+ type: 'boolean',
69
+ required: false,
70
+ default: 'false',
71
+ description: 'Wraps the checkbox in a bordered container. Use for standalone choices that need visual emphasis — plan cards, feature toggles, consent items. The border highlights with the accent colour when checked.',
72
+ },
73
+ {
74
+ name: 'helperText',
75
+ type: 'string',
76
+ required: false,
77
+ description: 'Secondary text below the label for additional context. The label becomes medium-weight for visual hierarchy.',
60
78
  },
61
79
  ],
62
80
  usageExamples: [
@@ -64,6 +82,8 @@ export const COMPONENT_MANIFEST = {
64
82
  { title: 'Uncontrolled', code: `<Checkbox defaultChecked label="Send me updates" />` },
65
83
  { title: 'Indeterminate', code: `<Checkbox indeterminate label="Select all" />` },
66
84
  { title: 'Disabled', code: `<Checkbox disabled label="Unavailable option" />` },
85
+ { title: 'Contained with helper', code: `<Checkbox contained label="Pro plan" helperText="Unlimited projects, 100 GB storage" />` },
86
+ { title: 'Contained standalone', code: `<Checkbox contained label="I accept the terms and conditions" />` },
67
87
  ],
68
88
  compositionGraph: [],
69
89
  accessibility: {
@@ -0,0 +1,45 @@
1
+ export const COMPONENT_MANIFEST = {
2
+ id: 'chip',
3
+ name: 'Chip',
4
+ tier: 'atom',
5
+ domain: 'neutral',
6
+ specVersion: '1.0',
7
+ description: 'A compact label for filters, tags, statuses, and categories. Combines the roles of Badge and Tag into a single flexible component.',
8
+ designIntent: 'Chip is the universal label primitive — use it anywhere you need a compact visual marker. ' +
9
+ 'It replaces both Badge (static status) and Tag (dismissible filter) with a single component. ' +
10
+ 'Use `onDismiss` for removable chips (filters, multi-select values). ' +
11
+ 'Use `onClick` for clickable/selectable chips (filter toggles, category navigation). ' +
12
+ 'Use `dot` for status indicators (online/offline). ' +
13
+ 'Use `swatch` for color-coded categories. ' +
14
+ 'Use `leftIcon` for chips with leading icons (folders, file types, flags). ' +
15
+ 'Use `borderless` for a softer, filled-only appearance in dense UIs. ' +
16
+ 'Variant conveys semantic meaning — default to neutral for user-generated content.',
17
+ props: [
18
+ { name: 'children', type: 'ReactNode', required: true, description: 'Chip label content.' },
19
+ { name: 'variant', type: 'enum', required: false, default: 'neutral', description: 'Colour scheme conveying semantic meaning.', enumValues: ['neutral', 'accent', 'success', 'warning', 'danger', 'info'] },
20
+ { name: 'size', type: 'enum', required: false, default: 'md', description: 'Controls height, font size, and icon size.', enumValues: ['sm', 'md', 'lg'] },
21
+ { name: 'onDismiss', type: 'function', required: false, description: 'Renders an x button that calls this handler. Use for removable filters and multi-select values.' },
22
+ { name: 'onClick', type: 'function', required: false, description: 'Makes the chip clickable (renders as <button>). Use for filter toggles and category links.' },
23
+ { name: 'leftIcon', type: 'ReactNode', required: false, description: 'Icon or element rendered before the label (emoji, flag, avatar).' },
24
+ { name: 'swatch', type: 'string', required: false, description: 'Hex color string. Renders a small color dot before the label.' },
25
+ { name: 'dot', type: 'boolean', required: false, default: 'false', description: 'Renders a status dot using the variant colour. Use for online/offline indicators.' },
26
+ { name: 'borderless', type: 'boolean', required: false, default: 'false', description: 'Removes the border for a filled-only look.' },
27
+ { name: 'disabled', type: 'boolean', required: false, default: 'false', description: 'Dims the chip and prevents interaction.' },
28
+ { name: 'style', type: 'object', required: false, description: 'Inline style overrides.' },
29
+ ],
30
+ usageExamples: [
31
+ { title: 'Dismissible filter', code: `<Chip onDismiss={() => removeFilter('react')}>React</Chip>` },
32
+ { title: 'Status with dot', code: `<Chip variant="success" dot>Online</Chip>` },
33
+ { title: 'Color swatch', code: `<Chip swatch="#6366f1" onDismiss={() => {}}>Indigo</Chip>` },
34
+ { title: 'With icon', code: `<Chip leftIcon={<FolderIcon />} onDismiss={() => {}}>Documents</Chip>` },
35
+ { title: 'Clickable category', code: `<Chip variant="accent" onClick={() => navigate('/ux')}>UX</Chip>` },
36
+ { title: 'Borderless', code: `<Chip variant="warning" borderless>Pending</Chip>` },
37
+ { title: 'Static label', code: `<Chip variant="info">Beta</Chip>` },
38
+ ],
39
+ compositionGraph: [],
40
+ accessibility: {
41
+ role: 'group',
42
+ notes: 'When onClick is provided, renders as <button> with native button semantics. Dismiss button has aria-label="Dismiss" and stopPropagation to prevent parent click handlers.',
43
+ keyboardInteractions: ['Enter / Space — activates onClick or dismiss button when focused'],
44
+ },
45
+ };
@@ -10,13 +10,16 @@ export const COMPONENT_MANIFEST = {
10
10
  'validation failures; the component applies danger styling automatically. ' +
11
11
  'leftElement and rightElement accept icons or small controls (e.g. currency symbol, clear button).',
12
12
  props: [
13
- { name: 'type', type: 'enum', required: false, default: 'text', description: 'HTML input type.', enumValues: ['text', 'number', 'password', 'email', 'tel', 'url', 'search'] },
13
+ { name: 'size', type: 'enum', required: false, default: 'md', description: 'Controls height, font size, and padding. Label and helper text scale accordingly.', enumValues: ['sm', 'md', 'lg'] },
14
+ { name: 'type', type: 'enum', required: false, default: 'text', description: 'HTML input type.', enumValues: ['text', 'number', 'password', 'email', 'tel', 'url', 'search', 'color'] },
14
15
  { name: 'label', type: 'string', required: false, description: 'Visible label rendered above the input.' },
15
16
  { name: 'helperText', type: 'string', required: false, description: 'Supplementary hint shown below the input.' },
16
17
  { name: 'errorText', type: 'string', required: false, description: 'Validation error message. When set, input renders in error state.' },
17
18
  { name: 'leftElement', type: 'ReactNode', required: false, description: 'Icon or adornment rendered inside the left edge.' },
18
19
  { name: 'rightElement', type: 'ReactNode', required: false, description: 'Icon or adornment rendered inside the right edge.' },
19
20
  { name: 'placeholder', type: 'string', required: false, description: 'Placeholder text. Use as a hint, not a label.' },
21
+ { name: 'prefix', type: 'ReactNode', required: false, description: 'Inset label attached to the left of the field (e.g. "$", "https://").' },
22
+ { name: 'suffix', type: 'ReactNode', required: false, description: 'Inset label attached to the right of the field (e.g. "kg", ".com").' },
20
23
  { name: 'disabled', type: 'boolean', required: false, default: 'false', description: 'Disables the input.' },
21
24
  { name: 'value', type: 'string', required: false, description: 'Controlled value.' },
22
25
  { name: 'onChange', type: 'function', required: false, description: 'Change handler.' },
@@ -35,8 +35,21 @@ export const COMPONENT_MANIFEST = {
35
35
  type: 'enum',
36
36
  required: false,
37
37
  default: 'md',
38
- description: 'Size of the radio button circle.',
39
- enumValues: ['sm', 'md'],
38
+ description: 'Size of the radio button circle and label text.',
39
+ enumValues: ['sm', 'md', 'lg'],
40
+ },
41
+ {
42
+ name: 'contained',
43
+ type: 'boolean',
44
+ required: false,
45
+ default: 'false',
46
+ description: 'Wraps the radio in a bordered container. Highlights with accent border and subtle background when selected. Use for plan/option cards where each choice needs visual emphasis.',
47
+ },
48
+ {
49
+ name: 'helperText',
50
+ type: 'string',
51
+ required: false,
52
+ description: 'Secondary text below the label for additional context. Label becomes medium-weight for visual hierarchy.',
40
53
  },
41
54
  ],
42
55
  usageExamples: [
@@ -56,6 +69,14 @@ export const COMPONENT_MANIFEST = {
56
69
  <Radio value="s" label="S" />
57
70
  <Radio value="m" label="M" />
58
71
  <Radio value="l" label="L" />
72
+ </RadioGroup>`.trim(),
73
+ },
74
+ {
75
+ title: 'Contained plan selector',
76
+ code: `
77
+ <RadioGroup name="plan" value={plan} onChange={setPlan}>
78
+ <Radio value="free" label="Free plan" helperText="Up to 3 projects" contained />
79
+ <Radio value="pro" label="Pro plan" helperText="Unlimited projects" contained />
59
80
  </RadioGroup>`.trim(),
60
81
  },
61
82
  {
@@ -18,6 +18,7 @@ export const COMPONENT_MANIFEST = {
18
18
  { name: 'value', type: 'string', required: false, description: 'Controlled value.' },
19
19
  { name: 'onChange', type: 'function', required: false, description: 'Change handler.' },
20
20
  { name: 'placeholder', type: 'string', required: false, description: 'Placeholder text.' },
21
+ { name: 'size', type: 'enum', required: false, default: 'md', description: 'Controls font size and padding.', enumValues: ['sm', 'md', 'lg'] },
21
22
  { name: 'disabled', type: 'boolean', required: false, default: 'false', description: 'Disables the textarea.' },
22
23
  ],
23
24
  usageExamples: [
@@ -44,6 +44,27 @@ export const COMPONENT_MANIFEST = {
44
44
  description: 'Controls the track and thumb size.',
45
45
  enumValues: ['sm', 'md', 'lg'],
46
46
  },
47
+ {
48
+ name: 'contained',
49
+ type: 'boolean',
50
+ required: false,
51
+ default: 'false',
52
+ description: 'Wraps the toggle in a bordered container. Highlights with accent border and subtle background when checked.',
53
+ },
54
+ {
55
+ name: 'helperText',
56
+ type: 'string',
57
+ required: false,
58
+ description: 'Secondary text below the label for additional context. Label becomes medium-weight for visual hierarchy.',
59
+ },
60
+ {
61
+ name: 'align',
62
+ type: 'enum',
63
+ required: false,
64
+ default: 'left',
65
+ description: 'Position of the toggle track relative to the label. Use "right" to push the track to the far end of the container.',
66
+ enumValues: ['left', 'right'],
67
+ },
47
68
  {
48
69
  name: 'disabled',
49
70
  type: 'boolean',
@@ -56,6 +77,8 @@ export const COMPONENT_MANIFEST = {
56
77
  { title: 'Controlled', code: `<Toggle checked={darkMode} onChange={e => setDarkMode(e.target.checked)} label="Dark mode" />` },
57
78
  { title: 'Uncontrolled', code: `<Toggle defaultChecked label="Email notifications" />` },
58
79
  { title: 'Sizes', code: `<Toggle size="sm" label="Compact" />\n<Toggle size="md" label="Default" />\n<Toggle size="lg" label="Large" />` },
80
+ { title: 'Contained with helper', code: `<Toggle contained label="Dark mode" helperText="Use dark colour scheme across the app" />` },
81
+ { title: 'Right-aligned', code: `<Toggle align="right" contained label="Notifications" helperText="Receive email alerts" />` },
59
82
  { title: 'Disabled', code: `<Toggle disabled label="Unavailable setting" />` },
60
83
  ],
61
84
  compositionGraph: [],
@@ -97,7 +97,7 @@ export const COMPONENT_MANIFEST = {
97
97
  },
98
98
  ],
99
99
  compositionGraph: [
100
- { componentId: 'tag', componentName: 'Tag', role: 'Selected value chips with dismiss button', required: true },
100
+ { componentId: 'chip', componentName: 'Chip', role: 'Selected value chips with dismiss button', required: true },
101
101
  { componentId: 'checkbox', componentName: 'Checkbox', role: 'Selection indicator in dropdown options', required: true },
102
102
  { componentId: 'text', componentName: 'Text', role: 'Option labels, empty state, and max hint', required: true },
103
103
  ],
@@ -23,6 +23,32 @@ export const COMPONENT_MANIFEST = {
23
23
  required: true,
24
24
  description: 'Called with the new string value whenever the input changes.',
25
25
  },
26
+ {
27
+ name: 'size',
28
+ type: 'enum',
29
+ required: false,
30
+ default: 'md',
31
+ description: 'Controls height and font size. Passed to the underlying Input.',
32
+ enumValues: ['sm', 'md', 'lg'],
33
+ },
34
+ {
35
+ name: 'label',
36
+ type: 'string',
37
+ required: false,
38
+ description: 'Visible label above the search field. Passed to the underlying Input.',
39
+ },
40
+ {
41
+ name: 'helperText',
42
+ type: 'string',
43
+ required: false,
44
+ description: 'Hint text below the field. Passed to the underlying Input.',
45
+ },
46
+ {
47
+ name: 'errorText',
48
+ type: 'string',
49
+ required: false,
50
+ description: 'Validation error text. Triggers error styling on the underlying Input.',
51
+ },
26
52
  {
27
53
  name: 'placeholder',
28
54
  type: 'string',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucent-ui",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "An AI-first React component library with machine-readable manifests.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",