@once-ui-system/core 2.0.0-alpha.0 → 2.0.0-alpha.1

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 (60) hide show
  1. package/AGENTS.md +1 -1
  2. package/LICENSE.md +21 -0
  3. package/ai/catalog.json +2 -2
  4. package/ai/eval-tasks.md +2 -1
  5. package/ai/examples/auth.tsx +1 -2
  6. package/ai/examples/blocks/Dashboard1.tsx +8 -8
  7. package/ai/examples/blocks/Feed3.tsx +4 -4
  8. package/ai/examples/blocks/Header2.tsx +1 -1
  9. package/ai/examples/blocks/Header4.tsx +1 -2
  10. package/ai/examples/blocks/Productivity1.tsx +1 -1
  11. package/ai/examples/blocks/Roadmap1.tsx +3 -3
  12. package/ai/examples/blocks/Sidebar1.tsx +1 -1
  13. package/ai/examples/blocks/Sidebar2.tsx +1 -1
  14. package/ai/examples/blocks/Table1.tsx +3 -3
  15. package/ai/examples/dashboard.tsx +5 -5
  16. package/ai/examples/marketing-hero.tsx +2 -2
  17. package/ai/examples/pricing.tsx +3 -3
  18. package/ai/examples/settings.tsx +4 -4
  19. package/ai/gotchas.json +19 -2
  20. package/ai/manifest.json +2 -2
  21. package/ai/recipes.md +1 -1
  22. package/ai/rules.compact.md +8 -2
  23. package/ai/rules.md +17 -5
  24. package/ai/spec.json +2 -2
  25. package/ai/tasks/settings.json +1 -1
  26. package/dist/AGENTS.md +1 -1
  27. package/dist/ai/catalog.json +2 -2
  28. package/dist/ai/eval-tasks.md +2 -1
  29. package/dist/ai/gotchas.json +19 -2
  30. package/dist/ai/manifest.json +2 -2
  31. package/dist/ai/recipes.md +1 -1
  32. package/dist/ai/rules.compact.md +8 -2
  33. package/dist/ai/rules.md +17 -5
  34. package/dist/ai/spec.json +2 -2
  35. package/dist/ai/tasks/settings.json +1 -1
  36. package/dist/components/Avatar.d.ts.map +1 -1
  37. package/dist/components/Avatar.js +1 -1
  38. package/dist/components/Avatar.js.map +1 -1
  39. package/dist/components/Carousel.js +1 -1
  40. package/dist/components/Carousel.js.map +1 -1
  41. package/dist/components/CountFx.d.ts.map +1 -1
  42. package/dist/components/CountFx.js +19 -7
  43. package/dist/components/CountFx.js.map +1 -1
  44. package/dist/components/DatePicker.js +2 -2
  45. package/dist/components/DatePicker.js.map +1 -1
  46. package/dist/components/EmojiPicker.js +1 -1
  47. package/dist/components/EmojiPicker.js.map +1 -1
  48. package/dist/components/OgCard.d.ts.map +1 -1
  49. package/dist/components/OgCard.js +7 -4
  50. package/dist/components/OgCard.js.map +1 -1
  51. package/dist/components/Select.js +1 -1
  52. package/dist/components/Select.js.map +1 -1
  53. package/dist/components/Table.js +2 -2
  54. package/dist/components/Table.js.map +1 -1
  55. package/dist/components/User.js +1 -1
  56. package/dist/components/User.js.map +1 -1
  57. package/dist/package.json +1 -1
  58. package/dist/scripts/validate-ai-code.js +239 -21
  59. package/package.json +1 -1
  60. package/scripts/validate-ai-code.js +239 -21
package/AGENTS.md CHANGED
@@ -47,7 +47,7 @@ If you cannot read `node_modules`, use the docs host (may not match your install
47
47
 
48
48
  - Use `Column` / `Row`, not `Flex` unless direction changes at breakpoints
49
49
  - Use `fill`, not `fillWidth fillHeight`; use `center`, not `horizontal="center" vertical="center"`
50
- - Static panels: `Column background="surface" border="neutral-alpha-weak" radius="l" padding="24"`
50
+ - Static panels: `Column background="surface" border radius="l" padding="24"`
51
51
  - `Card` is interactive only (`href` or `onClick`)
52
52
 
53
53
  Full rules: `@once-ui-system/core/ai/rules.compact.md`
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Dopler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/ai/catalog.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "2.0.0-alpha.0",
3
- "generated": "2026-09-16",
2
+ "version": "2.0.0-alpha.1",
3
+ "generated": "2026-09-17",
4
4
  "components": {
5
5
  "Accordion": {
6
6
  "group": "components",
package/ai/eval-tasks.md CHANGED
@@ -25,7 +25,8 @@ is found in the wild.
25
25
  Mechanical (count occurrences):
26
26
 
27
27
  - [ ] Compiles / no invented props or components
28
- - [ ] Redundant-default props (`position="relative"`, `variant="primary"` on Button, ...) — target: 0
28
+ - [ ] Redundant-default props (`position="relative"`, `variant="primary"` on Button, `fillWidth` beside `maxWidth`, `minWidth={0}` beside `fillWidth`, `border="neutral-alpha-weak"` for the default border, ...) — target: 0
29
+ - [ ] `zIndex` outside an isolated stacking group (nothing absolute/fixed/sticky nearby) — target: 0
29
30
  - [ ] Shorthand violations (`fillWidth fillHeight` instead of `fill`, `horizontal+vertical center` instead of `center`, `Flex direction=` instead of `Row`/`Column`) — target: 0
30
31
  - [ ] `style={{}}` uses where a token prop exists — target: 0
31
32
  - [ ] Raw HTML elements where a component exists (`img`, `a`, `button`) — target: 0
@@ -22,11 +22,10 @@ export function AuthExample() {
22
22
  return (
23
23
  <Column as="main" fillWidth center padding="24" minHeight="100vh">
24
24
  <Grid
25
- fillWidth
26
25
  maxWidth="l"
27
26
  columns="2"
28
27
  radius="xl"
29
- border="neutral-alpha-weak"
28
+ border
30
29
  overflow="hidden"
31
30
  background="surface"
32
31
  s={{ columns: 1 }}
@@ -37,7 +37,7 @@ const StatCard: React.FC<StatCardProps> = ({ title, value, change, positive = tr
37
37
  }, [positive]);
38
38
 
39
39
  return (
40
- <Card minWidth={12} href={href} paddingX="20" paddingTop="20" paddingBottom="80" radius="l" fillWidth direction="column" border="neutral-alpha-weak" background="transparent">
40
+ <Card minWidth={12} href={href} paddingX="20" paddingTop="20" paddingBottom="80" radius="l" fillWidth direction="column" border background="transparent">
41
41
  <LineChart
42
42
  pointerEvents="none"
43
43
  position="absolute"
@@ -82,7 +82,7 @@ interface ActivityItemProps {
82
82
  }
83
83
 
84
84
  const ActivityItem: React.FC<ActivityItemProps> = ({ avatar, action, time, href, icon }) => (
85
- <Row fillWidth borderBottom="neutral-alpha-weak">
85
+ <Row fillWidth borderBottom>
86
86
  <Card direction="column" fitHeight href={href} background="transparent" border="transparent" fillWidth>
87
87
  <Row fillWidth horizontal="between" paddingX="24" height="64" vertical="center">
88
88
  <Column fillWidth gap="8">
@@ -110,7 +110,7 @@ interface StatusItemProps {
110
110
  }
111
111
 
112
112
  const StatusItem: React.FC<StatusItemProps> = ({ name, status, icon, href = "#" }) => (
113
- <Row fillWidth borderBottom="neutral-alpha-weak">
113
+ <Row fillWidth borderBottom>
114
114
  <Card direction="column" background="transparent" href={href} border="transparent" fillWidth>
115
115
  <Row fillWidth horizontal="between" height="64" vertical="center" paddingX="24">
116
116
  <Row vertical="center" gap="12">
@@ -240,7 +240,7 @@ export const Dashboard1: React.FC = () => {
240
240
 
241
241
  <LineChart
242
242
  minHeight={20}
243
- border="neutral-alpha-weak"
243
+ border
244
244
  axis="x"
245
245
  grid="y"
246
246
  title="Revenue growth"
@@ -277,7 +277,7 @@ export const Dashboard1: React.FC = () => {
277
277
  />
278
278
 
279
279
  <Grid columns="2" m={{columns: 1}} gap="m" fillWidth>
280
- <Column fillWidth border="neutral-alpha-weak" radius="l" overflow="hidden" height={20}>
280
+ <Column fillWidth border radius="l" overflow="hidden" height={20}>
281
281
  <Row vertical="center" horizontal="between" fillWidth paddingLeft="24" paddingRight="12" paddingY="12" gap="m" wrap>
282
282
  <Heading wrap="nowrap" variant="heading-strong-s">
283
283
  Project status
@@ -295,7 +295,7 @@ export const Dashboard1: React.FC = () => {
295
295
  </Row>
296
296
  </Row>
297
297
 
298
- <Column fillWidth border="neutral-alpha-weak" topRadius="l" overflowY="auto">
298
+ <Column fillWidth border topRadius="l" overflowY="auto">
299
299
  {[
300
300
  { name: "Mobile App Development", status: "At Risk", icon: "code" as IconName },
301
301
  { name: "Marketing Campaign", status: "On Track", icon: "sparkle" as IconName },
@@ -314,7 +314,7 @@ export const Dashboard1: React.FC = () => {
314
314
  </Column>
315
315
  </Column>
316
316
 
317
- <Column border="neutral-alpha-weak" radius="l" fillWidth overflow="hidden" height={20}>
317
+ <Column border radius="l" fillWidth overflow="hidden" height={20}>
318
318
  <Row fillWidth vertical="center" horizontal="between" paddingLeft="24" paddingRight="12" paddingY="12" gap="16" wrap>
319
319
  <Heading wrap="nowrap" variant="heading-strong-s">
320
320
  Recent activity
@@ -323,7 +323,7 @@ export const Dashboard1: React.FC = () => {
323
323
  View all
324
324
  </Button>
325
325
  </Row>
326
- <Column fillWidth border="neutral-alpha-weak" topRadius="l" overflowY="auto">
326
+ <Column fillWidth border topRadius="l" overflowY="auto">
327
327
  {[
328
328
  {
329
329
  avatar: "/images/creators/lorant.jpg",
@@ -34,7 +34,7 @@ export const Feed3: React.FC<React.ComponentProps<typeof Column>> = ({ ...flex }
34
34
 
35
35
  return (
36
36
  <Column fill {...flex}>
37
- <Row fillWidth paddingX="24" paddingY="8" background="surface" borderBottom="neutral-alpha-weak" vertical="center" gap="12">
37
+ <Row fillWidth paddingX="24" paddingY="8" background="surface" borderBottom vertical="center" gap="12">
38
38
  <Text variant="label-default-s">👋 | intro</Text>
39
39
  <Row minWidth="4" minHeight="4" background="neutral-strong" radius="full"/>
40
40
  <Text variant="body-default-xs" onBackground="neutral-weak">Let us know a bit about you!</Text>
@@ -65,7 +65,7 @@ export const Feed3: React.FC<React.ComponentProps<typeof Column>> = ({ ...flex }
65
65
  key={aIdx}
66
66
  maxWidth={20}
67
67
  src={att.media}
68
- border="neutral-alpha-weak"
68
+ border
69
69
  radius="l"
70
70
  sizes="320px"
71
71
  />
@@ -75,9 +75,9 @@ export const Feed3: React.FC<React.ComponentProps<typeof Column>> = ({ ...flex }
75
75
  ) : (
76
76
  messages.attachments[0]?.media && (
77
77
  messages.attachments[0].media.includes("youtube.com") || messages.attachments[0].media.includes("youtu.be") ? (
78
- <Media maxWidth={32} border="neutral-alpha-weak" aspectRatio="16/9" marginTop="16" src={messages.attachments[0].media} radius="l" sizes="320px"/>
78
+ <Media maxWidth={32} border aspectRatio="16/9" marginTop="16" src={messages.attachments[0].media} radius="l" sizes="320px"/>
79
79
  ) : (messages.attachments[0].media.match(/\.(png|jpg|jpeg|gif|webp)$/i)) ? (
80
- <Media maxWidth={32} border="neutral-alpha-weak" marginTop="16" src={messages.attachments[0].media} radius="l" sizes="320px"/>
80
+ <Media maxWidth={32} border marginTop="16" src={messages.attachments[0].media} radius="l" sizes="320px"/>
81
81
  ) : (
82
82
  <Row maxWidth={24} marginTop="16">
83
83
  <OgCard url={messages.attachments[0].media} description={false} />
@@ -29,7 +29,7 @@ export const Header2: React.FC<HeaderProps> = ({ authenticated, avatar, ...flex
29
29
  />
30
30
  <Row
31
31
  as="header"
32
- border="neutral-alpha-weak"
32
+ border
33
33
  maxWidth="m"
34
34
  paddingX="m"
35
35
  radius="l"
@@ -39,8 +39,7 @@ export const Header4: React.FC<HeaderProps> = ({ cartCount = 0, ...flex }) => {
39
39
  <Row
40
40
  data-scaling="90"
41
41
  position="absolute"
42
- vertical="center"
43
- horizontal="center"
42
+ center
44
43
  textVariant="body-default-xs"
45
44
  solid="brand-strong"
46
45
  onSolid="brand-strong"
@@ -237,7 +237,7 @@ export const Productivity1 = () => {
237
237
  <Column
238
238
  key={index}
239
239
  minWidth={20}
240
- border="neutral-alpha-weak"
240
+ border
241
241
  fillWidth
242
242
  paddingX="4"
243
243
  radius="m-4"
@@ -79,7 +79,7 @@ export function Roadmap1() {
79
79
 
80
80
  <Row gap="4" fillWidth overflowX="auto" paddingBottom="16">
81
81
  {product.columns.map((column, columnIndex) => (
82
- <Column key={columnIndex} padding="4" gap="4" radius="s-4" border="neutral-alpha-weak" background="overlay" fillWidth minWidth={20}>
82
+ <Column key={columnIndex} padding="4" gap="4" radius="s-4" border background="overlay" fillWidth minWidth={20}>
83
83
  <Row fillWidth vertical="center" gap="8" paddingY="8" paddingX="16">
84
84
  <Text variant="label-default-m">
85
85
  {column.title}
@@ -99,7 +99,7 @@ export function Roadmap1() {
99
99
  return typedTask.href ? (
100
100
  <Card
101
101
  onBackground="neutral-strong"
102
- border="neutral-alpha-weak"
102
+ border
103
103
  fillWidth
104
104
  radius="s"
105
105
  key={taskIndex}
@@ -111,7 +111,7 @@ export function Roadmap1() {
111
111
  ) : (
112
112
  <Column
113
113
  onBackground="neutral-strong"
114
- border="neutral-alpha-weak"
114
+ border
115
115
  fillWidth
116
116
  radius="s"
117
117
  key={taskIndex}
@@ -16,7 +16,7 @@ export const Sidebar1: React.FC<React.ComponentProps<typeof Column>> = ({ ...fle
16
16
  fillHeight
17
17
  maxWidth={18}
18
18
  background="surface"
19
- borderRight="neutral-alpha-weak"
19
+ borderRight
20
20
  padding="8"
21
21
  gap="4"
22
22
  {...flex}
@@ -4,7 +4,7 @@ import { Column, Text, ToggleButton } from "@once-ui-system/core";
4
4
 
5
5
  /** Productivity sidebar — minimal stub for Productivity1 reference */
6
6
  export const Sidebar2: React.FC<React.ComponentProps<typeof Column>> = ({ ...flex }) => (
7
- <Column fillHeight maxWidth={18} background="surface" borderRight="neutral-alpha-weak" padding="8" gap="4" {...flex}>
7
+ <Column fillHeight maxWidth={18} background="surface" borderRight padding="8" gap="4" {...flex}>
8
8
  <Text variant="label-default-s" onBackground="neutral-weak" padding="12">
9
9
  Workspace
10
10
  </Text>
@@ -94,7 +94,7 @@ export const Table1: React.FC<Table1Props> = ({
94
94
  };
95
95
 
96
96
  return (
97
- <Column fillWidth radius="l" border="neutral-alpha-weak" {...flex}>
97
+ <Column fillWidth radius="l" border {...flex}>
98
98
  <Row fillWidth horizontal="between" paddingY="12" paddingRight="12" paddingLeft="24" gap="16" vertical="center" s={{direction: "column",}}>
99
99
  <Row fillWidth gap="12" vertical="center" horizontal="between">
100
100
  {selectable && someCurrentSelected ? (
@@ -124,8 +124,8 @@ export const Table1: React.FC<Table1Props> = ({
124
124
  )}
125
125
  </Row>
126
126
  <Column fillWidth overflowX="auto">
127
- <Column fillWidth radius="l" border="neutral-alpha-weak" overflow="hidden">
128
- <Row fillWidth gap="16" paddingX="24" paddingY="12" borderBottom="neutral-alpha-weak">
127
+ <Column fillWidth radius="l" border overflow="hidden">
128
+ <Row fillWidth gap="16" paddingX="24" paddingY="12" borderBottom>
129
129
  {selectable && (
130
130
  <Row textVariant="label-default-s" vertical="center" gap="16">
131
131
  <Checkbox
@@ -55,7 +55,7 @@ export function DashboardExample() {
55
55
 
56
56
  return (
57
57
  <Column as="main" fillWidth horizontal="center" paddingY="48" paddingX="24" gap="40">
58
- <Column fillWidth maxWidth="l" gap="40">
58
+ <Column maxWidth="l" gap="40">
59
59
  <Row fillWidth horizontal="between" vertical="end" gap="24" s={{ direction: "column", horizontal: "start" }}>
60
60
  <Column gap="8">
61
61
  <Text variant="label-default-s" onBackground="brand-medium">
@@ -79,7 +79,7 @@ export function DashboardExample() {
79
79
  <Grid ref={statsRef} columns="4" gap="16" m={{ columns: 2 }} s={{ columns: 1 }}>
80
80
  {stats.map((stat, index) => (
81
81
  <RevealFx key={stat.label} fill revealed={seen} translateY="8" delay={index * 100}>
82
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="16">
82
+ <Column background="surface" border radius="l" padding="24" gap="16">
83
83
  <Row fillWidth horizontal="between" vertical="center">
84
84
  <Text variant="label-default-s" onBackground="neutral-weak">
85
85
  {stat.label}
@@ -109,7 +109,7 @@ export function DashboardExample() {
109
109
  </Grid>
110
110
 
111
111
  <Grid columns="2" gap="24" s={{ columns: 1 }}>
112
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="16" minHeight={32}>
112
+ <Column background="surface" border radius="l" padding="24" gap="16" minHeight={32}>
113
113
  <Heading as="h2" variant="heading-strong-s">
114
114
  Revenue trend
115
115
  </Heading>
@@ -120,7 +120,7 @@ export function DashboardExample() {
120
120
  </Text>
121
121
  </Column>
122
122
  </Column>
123
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="16" minHeight={32}>
123
+ <Column background="surface" border radius="l" padding="24" gap="16" minHeight={32}>
124
124
  <Heading as="h2" variant="heading-strong-s">
125
125
  Signups by channel
126
126
  </Heading>
@@ -133,7 +133,7 @@ export function DashboardExample() {
133
133
  </Column>
134
134
  </Grid>
135
135
 
136
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="24">
136
+ <Column background="surface" border radius="l" padding="24" gap="24">
137
137
  <Row fillWidth horizontal="between" vertical="center">
138
138
  <Heading as="h2" variant="heading-strong-s">
139
139
  Recent activity
@@ -103,7 +103,7 @@ export function MarketingHeroExample() {
103
103
 
104
104
  {/* Feature grid — left-aligned section header, not repeated centered blocks */}
105
105
  <Column fillWidth horizontal="center">
106
- <Column fillWidth maxWidth="l" gap="40">
106
+ <Column maxWidth="l" gap="40">
107
107
  <Column gap="12" maxWidth={32}>
108
108
  <Text variant="label-default-s" onBackground="brand-medium">
109
109
  Components
@@ -117,7 +117,7 @@ export function MarketingHeroExample() {
117
117
  <Column
118
118
  key={feature.title}
119
119
  background="surface"
120
- border="neutral-alpha-weak"
120
+ border
121
121
  radius="l"
122
122
  padding="24"
123
123
  gap="16"
@@ -95,7 +95,7 @@ export function PricingExample() {
95
95
  </Column>
96
96
 
97
97
  <Column fillWidth horizontal="center">
98
- <Column fillWidth maxWidth="l" gap="40">
98
+ <Column maxWidth="l" gap="40">
99
99
  <Row fillWidth horizontal="between" vertical="end" gap="24" s={{ direction: "column", horizontal: "start" }}>
100
100
  <Heading as="h2" variant="display-strong-xs">
101
101
  Three plans, one decision
@@ -181,7 +181,7 @@ export function PricingExample() {
181
181
  </Column>
182
182
 
183
183
  <Column fillWidth horizontal="center" background="neutral-alpha-weak" paddingY="80" paddingX="24">
184
- <Column fillWidth maxWidth="l" gap="40">
184
+ <Column maxWidth="l" gap="40">
185
185
  <Heading as="h2" variant="display-strong-xs">
186
186
  Every feature, side by side
187
187
  </Heading>
@@ -203,7 +203,7 @@ export function PricingExample() {
203
203
  </Column>
204
204
 
205
205
  <Column fillWidth horizontal="center">
206
- <Column fillWidth maxWidth="l" radius="xl" border="neutral-alpha-weak" overflow="hidden" padding="64" center>
206
+ <Column maxWidth="l" radius="xl" border overflow="hidden" padding="64" center>
207
207
  <BlobFx position="absolute" top="0" left="0" fill opacity={60} seed={2} />
208
208
  <Column zIndex={1} center gap="24" maxWidth={40}>
209
209
  <Heading as="h2" variant="display-strong-s" align="center">
@@ -29,7 +29,7 @@ const sections = [
29
29
  export function SettingsExample() {
30
30
  return (
31
31
  <Column as="main" fillWidth horizontal="center" paddingY="48" paddingX="24">
32
- <Column fillWidth maxWidth="l" gap="40">
32
+ <Column maxWidth="l" gap="40">
33
33
  <Column gap="12">
34
34
  <Text variant="label-default-s" onBackground="brand-medium">
35
35
  Settings
@@ -46,7 +46,7 @@ export function SettingsExample() {
46
46
  gap="4"
47
47
  padding="16"
48
48
  background="surface"
49
- border="neutral-alpha-weak"
49
+ border
50
50
  radius="l"
51
51
  s={{ hide: true }}
52
52
  >
@@ -66,7 +66,7 @@ export function SettingsExample() {
66
66
  }
67
67
  rightPanel={
68
68
  <Column flex={1} gap="24">
69
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="24">
69
+ <Column background="surface" border radius="l" padding="24" gap="24">
70
70
  <Heading as="h2" variant="heading-strong-m">
71
71
  Profile
72
72
  </Heading>
@@ -97,7 +97,7 @@ export function SettingsExample() {
97
97
  </Row>
98
98
  </Column>
99
99
 
100
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="24">
100
+ <Column background="surface" border radius="l" padding="24" gap="24">
101
101
  <Heading as="h2" variant="heading-strong-m">
102
102
  Notifications
103
103
  </Heading>
package/ai/gotchas.json CHANGED
@@ -20,7 +20,7 @@
20
20
  ]
21
21
  },
22
22
  "Card.interactive": {
23
- "rule": "Card is for interactive surfaces only (href or onClick). Static panels use Column + background=\"surface\" border=\"neutral-alpha-weak\" radius=\"l\".",
23
+ "rule": "Card is for interactive surfaces only (href or onClick). Static panels use Column + background=\"surface\" border radius=\"l\".",
24
24
  "components": [
25
25
  "Card"
26
26
  ]
@@ -101,13 +101,30 @@
101
101
  ]
102
102
  },
103
103
  "layout.defaults": {
104
- "rule": "Never write props equal to defaults: position=\"relative\", direction on Row/Column, variant=\"primary\" on Button.",
104
+ "rule": "Never write props equal to defaults or implied by another prop on the element: position=\"relative\", direction on Row/Column, variant=\"primary\" on Button, fillWidth beside maxWidth (maxWidth already fills the width), minWidth={0} beside fillWidth (fillWidth already sets min-width: 0).",
105
105
  "components": [
106
106
  "Row",
107
107
  "Column",
108
+ "Grid",
108
109
  "Button"
109
110
  ]
110
111
  },
112
+ "border.default": {
113
+ "rule": "Bare border (and borderTop, borderBottom, borderX, …) draws the default border. Do not write border=\"neutral-alpha-weak\" to get it; name a colour only to deviate, e.g. border=\"brand-alpha-medium\".",
114
+ "components": [
115
+ "Row",
116
+ "Column",
117
+ "Card"
118
+ ]
119
+ },
120
+ "zIndex.scope": {
121
+ "rule": "zIndex is for an isolated stacking group: an absolute decorative layer and its content sibling (zIndex={1}), or a sticky header over its pane. Never on a lone element, never a page-wide ladder of 3 / 5 / 9 — restructure the tree instead.",
122
+ "components": [
123
+ "Row",
124
+ "Column",
125
+ "Background"
126
+ ]
127
+ },
111
128
  "section.gaps": {
112
129
  "rule": "Gap between page sections: 80–160 (typical 104). Inside sections: 24–40.",
113
130
  "components": [
package/ai/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "2.0.0-alpha.0",
3
- "generated": "2026-09-16",
2
+ "version": "2.0.0-alpha.1",
3
+ "generated": "2026-09-17",
4
4
  "files": {
5
5
  "spec": "spec.json",
6
6
  "catalog": "catalog.json",
package/ai/recipes.md CHANGED
@@ -87,7 +87,7 @@ For the emphasized item in a set (e.g. "most popular" pricing tier). Border + to
87
87
  Self-contained drifting brand/accent blobs (already blurred and pointer-transparent). Use behind a final CTA or feature visual — counts as continuous motion:
88
88
 
89
89
  ```tsx
90
- <Card fillWidth radius="l" border="neutral-alpha-weak" overflow="hidden" padding="48">
90
+ <Card fillWidth radius="l" border overflow="hidden" padding="48">
91
91
  <BlobFx position="absolute" top="0" left="0" fill opacity={60} seed={2} />
92
92
  <Column zIndex={1} center gap="24">
93
93
  {/* CTA content */}
@@ -11,6 +11,9 @@ Load with task bundle from `@once-ui-system/core/ai/tasks/{intent}.json`. For an
11
11
  | `fill` | `fillWidth fillHeight` |
12
12
  | `fit` | `fitWidth fitHeight` |
13
13
  | `center` | `horizontal="center" vertical="center"` |
14
+ | `maxWidth="l"` | `fillWidth maxWidth="l"` |
15
+ | `fillWidth` | `fillWidth minWidth={0}` |
16
+ | `border` | `border="neutral-alpha-weak"` |
14
17
 
15
18
  - `Flex` only when direction changes at breakpoints: `<Row s={{ direction: "column" }}>`
16
19
  - Page skeleton: `Column as="main" fillWidth horizontal="center"` → content `Column maxWidth="l"` → sections
@@ -22,9 +25,10 @@ Load with task bundle from `@once-ui-system/core/ai/tasks/{intent}.json`. For an
22
25
  Static panel recipe (pricing tiers, stats, settings sections):
23
26
 
24
27
  ```tsx
25
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="16">
28
+ <Column background="surface" border radius="l" padding="24" gap="16">
26
29
  ```
27
30
 
31
+ - Bare `border` (and `borderTop`, `borderBottom`, …) = the default border. Name a colour only to deviate: `border="brand-alpha-medium"`.
28
32
  - `Card` = interactive only (`href` or `onClick`). Static panels = Column + surface recipe.
29
33
  - Colors: `{scheme}-{weight}` or `{scheme}-alpha-{weight}`. Never hex/rgb.
30
34
  - `background` also: `surface | overlay | page | transparent`
@@ -40,6 +44,8 @@ Static panel recipe (pricing tiers, stats, settings sections):
40
44
 
41
45
  Absolute layers always: `position="absolute" top="0" left="0" fill pointerEvents="none"`, content `zIndex={1}`.
42
46
 
47
+ - `zIndex` only inside that layer group (or on a sticky header over its pane). Never on a lone element, never a page-wide ladder.
48
+
43
49
  - Gradient `width`: quarter-percent (400 = 100%). Glows: 100–200.
44
50
  - Glow colors: `brand-alpha-medium`, not `brand-background-weak`
45
51
  - Ambient layers on full-bleed section wrapper, outside `maxWidth` column
@@ -81,7 +87,7 @@ from `spec.json`.
81
87
 
82
88
  ## Defaults — omit these
83
89
 
84
- `position="relative"`, `direction` on Row/Column, `variant="primary"` on Button, `size="m"` when default.
90
+ `position="relative"`, `direction` on Row/Column, `variant="primary"` on Button, `size="m"` when default, `fillWidth` beside `maxWidth`, `minWidth={0}` beside `fillWidth`, a border colour that restates the default.
85
91
 
86
92
  ## Before building
87
93
 
package/ai/rules.md CHANGED
@@ -40,10 +40,22 @@ If you can't ask (or the user says "you decide"), default to: restrained, center
40
40
  <Row fillWidth fillHeight horizontal="center" vertical="center">...</Row>
41
41
  ```
42
42
 
43
- 3. Never write a prop that equals its default. The spec marks defaults with `= value`. Common offenders:
43
+ 3. Never write a prop that equals its default, or one that another prop on the same element already implies. The spec marks defaults with `= value`. Common offenders:
44
44
  - `position="relative"` (default on all layout components)
45
45
  - `direction="row"` on `Row`, `direction="column"` on `Column`
46
46
  - `variant="primary"`, `size="m"` on `Button`
47
+ - `fillWidth` beside `maxWidth` — `maxWidth` already fills the width up to the cap
48
+ - `minWidth={0}` beside `fillWidth` — `fillWidth` already sets `min-width: 0`
49
+ - a colour on `border` (or `borderTop`, `borderBottom`, `borderX`, …) that only restates the default — bare `border` draws the default border; name a colour only to deviate from it
50
+
51
+ ```tsx
52
+ // Good
53
+ <Column maxWidth="l" border radius="l">
54
+ // Bad
55
+ <Column fillWidth maxWidth="l" minWidth={0} position="relative" border="neutral-alpha-weak" radius="l">
56
+ ```
57
+
58
+ 3b. `zIndex` belongs to a stacking group, not to a page. Use it only inside an isolated group that needs an order — a decorative absolute layer and the content sibling above it (rule 21), a sticky header over the pane it covers — and keep the values small within that group. A `zIndex` on a lone element, or a page-wide ladder of `zIndex={3}`, `{5}`, `{9}`, means the hierarchy is being managed by hand; restructure the tree instead.
47
59
 
48
60
  ## Spacing and sizing
49
61
 
@@ -66,10 +78,10 @@ If you can't ask (or the user says "you decide"), default to: restrained, center
66
78
  - `background` also accepts `surface | overlay | page | transparent`
67
79
  - `onBackground` colors text/icons on a background
68
80
 
69
- 8. Standard surface recipe: `background="surface"` (or `"overlay"` over imagery) + `border="neutral-alpha-weak"` (or `-medium`) + `radius="l"`.
81
+ 8. Standard surface recipe: `background="surface"` (or `"overlay"` over imagery) + `border` + `radius="l"`. Bare `border` is the default border; name a colour (`border="neutral-alpha-medium"`, `border="brand-alpha-medium"`) only when the surface should differ from it.
70
82
 
71
83
  ```tsx
72
- <Column background="surface" border="neutral-alpha-weak" radius="l" padding="24" gap="16">
84
+ <Column background="surface" border radius="l" padding="24" gap="16">
73
85
  ```
74
86
 
75
87
  ## Text
@@ -183,7 +195,7 @@ the card it was meant to support.
183
195
  <Grid columns={5} s={{ columns: 3 }} gap="8" fillWidth>
184
196
  {items.map(i => (
185
197
  <Column key={i} aspectRatio="1 / 1" padding="12" radius="l"
186
- background="page" border="neutral-alpha-weak" vertical="between">
198
+ background="page" border vertical="between">
187
199
  {/* a preview of the thing, not just its name */}
188
200
  </Column>
189
201
  ))}
@@ -204,7 +216,7 @@ in that order.
204
216
  <Background position="absolute" top="0" left="0" fill pointerEvents="none" ... />
205
217
  ```
206
218
 
207
- Siblings holding content get `zIndex={1}`. `overflow="hidden"` goes on the parent **only when it has a radius** (cards, panels) — clipping a full-bleed section turns the glow into a hard-edged band.
219
+ Siblings holding content get `zIndex={1}`. That layer and its content sibling are the whole stacking group — nothing else in the section needs a `zIndex` (rule 3b). `overflow="hidden"` goes on the parent **only when it has a radius** (cards, panels) — clipping a full-bleed section turns the glow into a hard-edged band.
208
220
 
209
221
  21b. Ambient section layers (hero glows) live on the **full-width section wrapper**, outside the `maxWidth` content column, with generous room (`paddingY="80"`+). Inside a narrow container the gradient gets clipped at the container edge and reads as a misplaced card:
210
222
 
package/ai/spec.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@once-ui-system/core",
3
- "version": "2.0.0-alpha.0",
4
- "generated": "2026-09-16",
3
+ "version": "2.0.0-alpha.1",
4
+ "generated": "2026-09-17",
5
5
  "format": "props are 'type', 'type = default', or '!type' (required). Components with 'mixins' also accept all props of those mixins. 'extends' means all props of that component are accepted. In 'types', an array lists a union's allowed values, an object gives a shape's fields in the same notation as props, and a string is the type as written — usually pointing at a component whose props are already listed.",
6
6
  "tokens": {
7
7
  "StaticSpacingToken": "\"0\" | \"1\" | \"2\" | \"4\" | \"8\" | \"12\" | \"16\" | \"20\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"104\" | \"128\" | \"160\"",
@@ -28,7 +28,7 @@
28
28
  "layout.defaults"
29
29
  ],
30
30
  "quality": {
31
- "surfaceRecipe": "background=\"surface\" border=\"neutral-alpha-weak\" radius=\"l\" padding=\"24\"",
31
+ "surfaceRecipe": "background=\"surface\" border radius=\"l\" padding=\"24\"",
32
32
  "dangerZone": "border=\"danger-alpha-medium\" on danger actions only"
33
33
  }
34
34
  }
package/dist/AGENTS.md CHANGED
@@ -47,7 +47,7 @@ If you cannot read `node_modules`, use the docs host (may not match your install
47
47
 
48
48
  - Use `Column` / `Row`, not `Flex` unless direction changes at breakpoints
49
49
  - Use `fill`, not `fillWidth fillHeight`; use `center`, not `horizontal="center" vertical="center"`
50
- - Static panels: `Column background="surface" border="neutral-alpha-weak" radius="l" padding="24"`
50
+ - Static panels: `Column background="surface" border radius="l" padding="24"`
51
51
  - `Card` is interactive only (`href` or `onClick`)
52
52
 
53
53
  Full rules: `@once-ui-system/core/ai/rules.compact.md`
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "2.0.0-alpha.0",
3
- "generated": "2026-09-16",
2
+ "version": "2.0.0-alpha.1",
3
+ "generated": "2026-09-17",
4
4
  "components": {
5
5
  "Accordion": {
6
6
  "group": "components",
@@ -25,7 +25,8 @@ is found in the wild.
25
25
  Mechanical (count occurrences):
26
26
 
27
27
  - [ ] Compiles / no invented props or components
28
- - [ ] Redundant-default props (`position="relative"`, `variant="primary"` on Button, ...) — target: 0
28
+ - [ ] Redundant-default props (`position="relative"`, `variant="primary"` on Button, `fillWidth` beside `maxWidth`, `minWidth={0}` beside `fillWidth`, `border="neutral-alpha-weak"` for the default border, ...) — target: 0
29
+ - [ ] `zIndex` outside an isolated stacking group (nothing absolute/fixed/sticky nearby) — target: 0
29
30
  - [ ] Shorthand violations (`fillWidth fillHeight` instead of `fill`, `horizontal+vertical center` instead of `center`, `Flex direction=` instead of `Row`/`Column`) — target: 0
30
31
  - [ ] `style={{}}` uses where a token prop exists — target: 0
31
32
  - [ ] Raw HTML elements where a component exists (`img`, `a`, `button`) — target: 0