@godxjp/ui 27.3.1 → 27.5.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.
- package/dist/components/data-entry/upload-file-kind.d.ts +25 -0
- package/dist/components/data-entry/upload-file-kind.js +88 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +10 -6
- package/dist/components/general/icon.d.ts +31 -0
- package/dist/components/general/icon.js +23 -0
- package/dist/components/general/index.d.ts +2 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/layout/flex.d.ts +2 -2
- package/dist/components/layout/flex.js +7 -1
- package/dist/components/layout/topbar-item.d.ts +1 -0
- package/dist/components/layout/topbar-item.js +3 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/avatar.js +2 -0
- package/dist/components/ui/segmented.d.ts +7 -2
- package/dist/components/ui/toggle.d.ts +2 -2
- package/dist/components/ui/toggle.js +4 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/components/data-display.prop.d.ts +14 -0
- package/dist/props/components/data-entry.prop.d.ts +25 -0
- package/dist/props/components/general.prop.d.ts +42 -1
- package/dist/props/components/layout.prop.d.ts +42 -0
- package/dist/props/registry.d.ts +37 -1
- package/dist/props/registry.js +43 -1
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +11 -0
- package/dist/styles/control.css +12 -0
- package/dist/styles/core.css +2 -0
- package/dist/styles/data-display-layout.css +35 -5
- package/dist/styles/data-entry-layout.css +22 -0
- package/dist/styles/icon-layout.css +37 -0
- package/dist/styles/index.css +2 -0
- package/dist/styles/shell-layout.css +10 -0
- package/dist/styles/text-layout.css +16 -8
- package/dist/tokens/components/control.css +1 -0
- package/dist/tokens/components/data-display.css +26 -0
- package/dist/tokens/components/segmented.css +4 -0
- package/dist/tokens/components/upload.css +4 -0
- package/docs/CONSUMER-RULES.md +2 -2
- package/docs/CUSTOMER-THEMING.md +26 -0
- package/docs/FRAME-COVERAGE-REPORT.md +3 -2
- package/docs/data-display/avatar.tsx +128 -11
- package/docs/data-display/prose.tsx +64 -0
- package/docs/data-entry/segmented.tsx +55 -5
- package/docs/data-entry/toggle-group.tsx +15 -3
- package/docs/data-entry/toggle.tsx +39 -1
- package/docs/data-entry/upload.tsx +38 -0
- package/docs/general/icon.tsx +215 -0
- package/docs/layout/flex.tsx +59 -0
- package/docs/layout/topbar-item.tsx +29 -1
- package/package.json +2 -2
- package/scripts/consumer-rule.md +18 -17
- package/scripts/ui-audit.mjs +128 -0
package/dist/props/registry.d.ts
CHANGED
|
@@ -434,6 +434,11 @@ export declare const VOCABULARY_REGISTRY: {
|
|
|
434
434
|
readonly category: "interaction";
|
|
435
435
|
readonly description: "Text size — golden-ratio type-scale steps (2xs…2xl), never an arbitrary px";
|
|
436
436
|
};
|
|
437
|
+
readonly IconSizeProp: {
|
|
438
|
+
readonly file: "vocabulary/interaction.prop.ts";
|
|
439
|
+
readonly category: "interaction";
|
|
440
|
+
readonly description: "Icon size — the nine --icon-size-* scale steps (2xs…4xl), never an arbitrary px or a size- utility";
|
|
441
|
+
};
|
|
437
442
|
readonly TextToneProp: {
|
|
438
443
|
readonly file: "vocabulary/interaction.prop.ts";
|
|
439
444
|
readonly category: "interaction";
|
|
@@ -746,6 +751,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
746
751
|
readonly file: "components/layout.prop.ts";
|
|
747
752
|
readonly vocabulary: readonly [];
|
|
748
753
|
};
|
|
754
|
+
readonly FlexMarkerProp: {
|
|
755
|
+
readonly group: "layout";
|
|
756
|
+
readonly file: "components/layout.prop.ts";
|
|
757
|
+
readonly vocabulary: readonly [];
|
|
758
|
+
};
|
|
749
759
|
readonly FlexAlignProp: {
|
|
750
760
|
readonly group: "layout";
|
|
751
761
|
readonly file: "components/layout.prop.ts";
|
|
@@ -767,6 +777,10 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
767
777
|
readonly field: "direction";
|
|
768
778
|
readonly local: true;
|
|
769
779
|
readonly reason: "Flex-specific axis control.";
|
|
780
|
+
}, {
|
|
781
|
+
readonly field: "marker";
|
|
782
|
+
readonly local: true;
|
|
783
|
+
readonly reason: 'List-marker seam for as="ul"/"ol" (disc | decimal | none). marker="none" emits no data-list, so a list keeps its element, its <li> semantics and its gap token while losing the bullet and the --space-5 indent — the home <ListRow as="li"> had none of, which forced a raw <ul> (gh#714).';
|
|
770
784
|
}, "GapProp", {
|
|
771
785
|
readonly field: "align";
|
|
772
786
|
readonly local: true;
|
|
@@ -1203,6 +1217,23 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1203
1217
|
readonly reason: "Ambient live-region opt-in — ActivityAnnounceProp vocabulary; deliberately NOT a boolean so the value names the politeness level.";
|
|
1204
1218
|
}];
|
|
1205
1219
|
};
|
|
1220
|
+
readonly IconGlyphProp: {
|
|
1221
|
+
readonly group: "general";
|
|
1222
|
+
readonly file: "components/general.prop.ts";
|
|
1223
|
+
readonly vocabulary: readonly ["IconProp", "IconSizeProp", "TextToneProp", "LabelProp", "ClassNameProp", {
|
|
1224
|
+
readonly field: "label";
|
|
1225
|
+
readonly local: true;
|
|
1226
|
+
readonly reason: "LabelProp narrowed to string: this becomes the glyph's aria-label, and an accessible name is TEXT — a ReactNode cannot be one.";
|
|
1227
|
+
}, {
|
|
1228
|
+
readonly field: "as";
|
|
1229
|
+
readonly local: true;
|
|
1230
|
+
readonly reason: "The glyph COMPONENT to render — the IconProp concept, widened to a component that also forwards SVG props and a ref, because Icon renders ONTO the glyph (the sized element is the <svg> itself) rather than wrapping it.";
|
|
1231
|
+
}, {
|
|
1232
|
+
readonly field: "size";
|
|
1233
|
+
readonly local: true;
|
|
1234
|
+
readonly reason: "IconSizeProp, the nine-step icon scale — deliberately NOT the four-step control SizeProp: a glyph beside 2xs caption text and a 48px empty-state mark are the same primitive.";
|
|
1235
|
+
}];
|
|
1236
|
+
};
|
|
1206
1237
|
readonly FloatButtonTypeProp: {
|
|
1207
1238
|
readonly group: "general";
|
|
1208
1239
|
readonly file: "components/general.prop.ts";
|
|
@@ -1619,6 +1650,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1619
1650
|
readonly file: "components/data-entry.prop.ts";
|
|
1620
1651
|
readonly vocabulary: readonly [];
|
|
1621
1652
|
};
|
|
1653
|
+
readonly UploadListTypeProp: {
|
|
1654
|
+
readonly group: "data-entry";
|
|
1655
|
+
readonly file: "components/data-entry.prop.ts";
|
|
1656
|
+
readonly vocabulary: readonly [];
|
|
1657
|
+
};
|
|
1622
1658
|
readonly TreeOptionProp: {
|
|
1623
1659
|
readonly group: "data-entry";
|
|
1624
1660
|
readonly file: "components/data-entry.prop.ts";
|
|
@@ -1677,7 +1713,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1677
1713
|
readonly AvatarProp: {
|
|
1678
1714
|
readonly group: "data-display";
|
|
1679
1715
|
readonly file: "components/data-display.prop.ts";
|
|
1680
|
-
readonly vocabulary: readonly ["AvatarShapeProp", "LabelProp", "ChildrenProp", "ClassNameProp"];
|
|
1716
|
+
readonly vocabulary: readonly ["AvatarShapeProp", "SizeProp", "LabelProp", "ChildrenProp", "ClassNameProp"];
|
|
1681
1717
|
};
|
|
1682
1718
|
readonly AvatarAppearanceProp: {
|
|
1683
1719
|
readonly group: "data-display";
|
package/dist/props/registry.js
CHANGED
|
@@ -433,6 +433,11 @@ const VOCABULARY_REGISTRY = {
|
|
|
433
433
|
category: "interaction",
|
|
434
434
|
description: "Text size \u2014 golden-ratio type-scale steps (2xs\u20262xl), never an arbitrary px"
|
|
435
435
|
},
|
|
436
|
+
IconSizeProp: {
|
|
437
|
+
file: "vocabulary/interaction.prop.ts",
|
|
438
|
+
category: "interaction",
|
|
439
|
+
description: "Icon size \u2014 the nine --icon-size-* scale steps (2xs\u20264xl), never an arbitrary px or a size- utility"
|
|
440
|
+
},
|
|
436
441
|
TextToneProp: {
|
|
437
442
|
file: "vocabulary/interaction.prop.ts",
|
|
438
443
|
category: "interaction",
|
|
@@ -767,6 +772,7 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
767
772
|
]
|
|
768
773
|
},
|
|
769
774
|
FlexDirectionProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
|
|
775
|
+
FlexMarkerProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
|
|
770
776
|
FlexAlignProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
|
|
771
777
|
FlexJustifyProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
|
|
772
778
|
FlexProp: {
|
|
@@ -779,6 +785,11 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
779
785
|
reason: "Closed tag seam (div | span) so a Flex stays valid HTML inside a phrasing-only parent such as the <button> a TabsTrigger renders \u2014 same shape as ListRow's `as` (gh#354)."
|
|
780
786
|
},
|
|
781
787
|
{ field: "direction", local: true, reason: "Flex-specific axis control." },
|
|
788
|
+
{
|
|
789
|
+
field: "marker",
|
|
790
|
+
local: true,
|
|
791
|
+
reason: 'List-marker seam for as="ul"/"ol" (disc | decimal | none). marker="none" emits no data-list, so a list keeps its element, its <li> semantics and its gap token while losing the bullet and the --space-5 indent \u2014 the home <ListRow as="li"> had none of, which forced a raw <ul> (gh#714).'
|
|
792
|
+
},
|
|
782
793
|
"GapProp",
|
|
783
794
|
{ field: "align", local: true, reason: "Flex-specific align-items keyword subset." },
|
|
784
795
|
{ field: "justify", local: true, reason: "Flex-specific justify-content keyword subset." },
|
|
@@ -1328,6 +1339,32 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1328
1339
|
}
|
|
1329
1340
|
]
|
|
1330
1341
|
},
|
|
1342
|
+
IconGlyphProp: {
|
|
1343
|
+
group: "general",
|
|
1344
|
+
file: "components/general.prop.ts",
|
|
1345
|
+
vocabulary: [
|
|
1346
|
+
"IconProp",
|
|
1347
|
+
"IconSizeProp",
|
|
1348
|
+
"TextToneProp",
|
|
1349
|
+
"LabelProp",
|
|
1350
|
+
"ClassNameProp",
|
|
1351
|
+
{
|
|
1352
|
+
field: "label",
|
|
1353
|
+
local: true,
|
|
1354
|
+
reason: "LabelProp narrowed to string: this becomes the glyph's aria-label, and an accessible name is TEXT \u2014 a ReactNode cannot be one."
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
field: "as",
|
|
1358
|
+
local: true,
|
|
1359
|
+
reason: "The glyph COMPONENT to render \u2014 the IconProp concept, widened to a component that also forwards SVG props and a ref, because Icon renders ONTO the glyph (the sized element is the <svg> itself) rather than wrapping it."
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
field: "size",
|
|
1363
|
+
local: true,
|
|
1364
|
+
reason: "IconSizeProp, the nine-step icon scale \u2014 deliberately NOT the four-step control SizeProp: a glyph beside 2xs caption text and a 48px empty-state mark are the same primitive."
|
|
1365
|
+
}
|
|
1366
|
+
]
|
|
1367
|
+
},
|
|
1331
1368
|
FloatButtonTypeProp: {
|
|
1332
1369
|
group: "general",
|
|
1333
1370
|
file: "components/general.prop.ts",
|
|
@@ -1898,6 +1935,11 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1898
1935
|
vocabulary: []
|
|
1899
1936
|
},
|
|
1900
1937
|
UploadVariantProp: { group: "data-entry", file: "components/data-entry.prop.ts", vocabulary: [] },
|
|
1938
|
+
UploadListTypeProp: {
|
|
1939
|
+
group: "data-entry",
|
|
1940
|
+
file: "components/data-entry.prop.ts",
|
|
1941
|
+
vocabulary: []
|
|
1942
|
+
},
|
|
1901
1943
|
TreeOptionProp: {
|
|
1902
1944
|
group: "data-entry",
|
|
1903
1945
|
file: "components/data-entry.prop.ts",
|
|
@@ -2005,7 +2047,7 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
2005
2047
|
AvatarProp: {
|
|
2006
2048
|
group: "data-display",
|
|
2007
2049
|
file: "components/data-display.prop.ts",
|
|
2008
|
-
vocabulary: ["AvatarShapeProp", "LabelProp", "ChildrenProp", "ClassNameProp"]
|
|
2050
|
+
vocabulary: ["AvatarShapeProp", "SizeProp", "LabelProp", "ChildrenProp", "ClassNameProp"]
|
|
2009
2051
|
},
|
|
2010
2052
|
AvatarAppearanceProp: {
|
|
2011
2053
|
group: "data-display",
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
export type { ClassNameProp, ChildrenProp, IdProp, OpenProp, DefaultOpenProp, OnOpenChangeProp, HandlerProp, PendingProp, RequiredProp, DisabledProp, LabelProp, HelperProp, ErrorProp, ErrorBagProp, PlaceholderProp, NameProp, ValueProp, DefaultValueProp, OnValueChangeProp, OnChangeProp, OnClickProp, AsChildProp, FlushProp, WidthProp, ControlWidthProp, AllowClearProp, MaxTagCountProp, MaxTagPlaceholderProp, NotFoundContentProp, PopupMatchWidthProp, } from "./shared.prop.js";
|
|
3
3
|
export type { TitleProp, SubtitleProp, StatusProp, DescriptionProp, ExtraProp, FooterProp, ActionProp, IconProp, ConfirmLabelProp, CancelLabelProp, ActionsProp, EmptyMessageProp, } from "./content.prop.js";
|
|
4
4
|
export type { PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, CenteredShellPresetProp, ErrorSurfaceModeProp, ErrorSurfaceStatusProp, AuthShellPresetProp, MobileShellHeightProp, MobileShellWidthProp, OrientationProp, TableDensityProp, DensityProp, GapNameProp, PadProp, PadRawProp, PadSides, GapProp, GapStepProp, } from "./layout.prop.js";
|
|
5
|
-
export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, AppSettingToggleAppearanceProp, ShapeProp, AvatarShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, TextWhitespaceProp, TypographyTypeProp, TitleLevelProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyActionsConfigProp, SizeProp, ControlStatusProp, ControlVariantProp, FormLayoutProp, DescriptionsLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, ActivityVariantProp, ActivityAnnounceProp, } from "./interaction.prop.js";
|
|
5
|
+
export type { ButtonVariantProp, ButtonSizeProp, BadgeVariantProp, AppSettingPickerAppearanceProp, AppSettingToggleAppearanceProp, ShapeProp, AvatarShapeProp, TextSizeProp, TextToneProp, FontWeightProp, HeadingLevelProp, TextAlignProp, TextWhitespaceProp, TypographyTypeProp, TitleLevelProp, TypographyCopyConfigProp, TypographyEditConfigProp, TypographyEllipsisConfigProp, TypographyActionsConfigProp, SizeProp, ControlStatusProp, ControlVariantProp, FormLayoutProp, DescriptionsLayoutProp, BreakpointProp, ConfirmVariantProp, ToneProp, AlertVariantProp, SortDirectionProp, ColumnAlignProp, SortStateProp, RevealDelayProp, ActivityVariantProp, ActivityAnnounceProp, IconSizeProp, } from "./interaction.prop.js";
|
|
6
6
|
export type { BreadcrumbItemProp, BreadcrumbProp, BreadcrumbItemMenuProp, BreadcrumbItemMenuEntryProp, BreadcrumbSeparatorProp, BreadcrumbItemRenderProp, } from "./navigation.prop.js";
|
|
7
7
|
export type { GetRowIdProp, GetRowLabelProp, OnRowClickProp, ColumnDefProp, TablePresetProp, TableColumnPriorityProp, TableCellIndentProp, SelectedIdsProp, OnSelectChangeProp, OnTableDensityChangeProp, TableRowToneProp, RowToneProp, OnSortChangeProp, OnSearchChangeProp, OnClearFiltersProp, HasActiveFiltersProp, StickyProp, ColumnFixedProp, ColumnFilterValueProp, ColumnFilterItemProp, ColumnFilterStateProp, OnColumnFilterChangeProp, ColumnCompareProp, ColumnSorterProp, TableSelectionItemProp, TableRowSelectionProp, TableExpandableProp, TableSummaryProp, TableScrollProp, TableStickyProp, OnRowProp, TablePaginationProp, TablePaginationPositionProp, DescriptionsColumnProp, DescriptionsSpanProp, DescriptionsItemsProp, } from "./data.prop.js";
|
|
@@ -31,6 +31,17 @@ export type ShapeProp = "default" | "pill" | "sharp";
|
|
|
31
31
|
export type AvatarShapeProp = "circle" | "square";
|
|
32
32
|
/** Text size — steps of the golden-ratio type scale (NEVER an arbitrary px). `sm` = base. */
|
|
33
33
|
export type TextSizeProp = "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
|
|
34
|
+
/**
|
|
35
|
+
* Icon size — the NINE steps of the `--icon-size-*` scale (docs/TOKENS.md · gh#326), not the four
|
|
36
|
+
* of the control `SizeProp`.
|
|
37
|
+
*
|
|
38
|
+
* The icon axis already had a vocabulary before it had a name, and it is a FIXED LIST rather than
|
|
39
|
+
* a ratio: 14/16 = 0.875 but 20/16 = 1.25, because a 1px-stroke glyph cannot sit on half a pixel.
|
|
40
|
+
* Naming the whole list here — as `TextSizeProp` does for type — is what lets a consumer put a
|
|
41
|
+
* standalone glyph on the scale (`<Icon as={Lock} size="sm" />`) instead of reaching for a
|
|
42
|
+
* `className="size-4"` the consumer rules forbid.
|
|
43
|
+
*/
|
|
44
|
+
export type IconSizeProp = "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
|
|
34
45
|
/** Text colour intent — maps to semantic foreground tokens (no raw palette). */
|
|
35
46
|
/**
|
|
36
47
|
* `inherit` is the one that is NOT a colour: it takes whatever the surface already set (gh#643).
|
package/dist/styles/control.css
CHANGED
|
@@ -31,6 +31,12 @@
|
|
|
31
31
|
padding-inline: var(--space-3);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
.ui-toggle-xs {
|
|
35
|
+
min-height: var(--control-height-xs);
|
|
36
|
+
padding-inline: var(--space-1);
|
|
37
|
+
font-size: var(--toggle-xs-font-size);
|
|
38
|
+
}
|
|
39
|
+
|
|
34
40
|
.ui-toggle-sm {
|
|
35
41
|
min-height: var(--control-height-sm);
|
|
36
42
|
padding-inline: var(--space-2);
|
|
@@ -3135,6 +3141,12 @@
|
|
|
3135
3141
|
justify-content: flex-start;
|
|
3136
3142
|
}
|
|
3137
3143
|
|
|
3144
|
+
.ui-segmented[data-size="xs"] {
|
|
3145
|
+
--control-height: var(--control-height-xs);
|
|
3146
|
+
--segmented-item-padding-inline: var(--segmented-xs-item-padding-inline);
|
|
3147
|
+
font-size: var(--segmented-xs-font-size);
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3138
3150
|
.ui-segmented[data-size="sm"] {
|
|
3139
3151
|
--control-height: var(--control-height-sm);
|
|
3140
3152
|
}
|
package/dist/styles/core.css
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
.ui-avatar {
|
|
3
3
|
position: relative;
|
|
4
4
|
display: inline-flex;
|
|
5
|
-
width: var(--
|
|
6
|
-
height: var(--
|
|
5
|
+
width: var(--avatar-size);
|
|
6
|
+
height: var(--avatar-size);
|
|
7
7
|
flex-shrink: 0;
|
|
8
8
|
align-items: center;
|
|
9
9
|
justify-content: center;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
linear-gradient(var(--avatar-tint), var(--avatar-tint)),
|
|
14
14
|
var(--avatar-background, hsl(var(--muted)));
|
|
15
15
|
color: hsl(var(--muted-foreground));
|
|
16
|
-
font-size: var(--font-size
|
|
16
|
+
font-size: var(--avatar-font-size);
|
|
17
17
|
font-weight: var(--font-weight-medium);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -36,6 +36,36 @@
|
|
|
36
36
|
flex: none;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
.ui-avatar[data-size="xs"] {
|
|
40
|
+
--avatar-size: var(--avatar-size-xs);
|
|
41
|
+
--avatar-square-size: var(--avatar-size-xs);
|
|
42
|
+
--avatar-font-size: var(--avatar-font-size-xs);
|
|
43
|
+
--avatar-glyph-size: var(--avatar-glyph-size-xs);
|
|
44
|
+
--avatar-tinted-glyph-size: var(--avatar-glyph-size-xs);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ui-avatar[data-size="sm"] {
|
|
48
|
+
--avatar-size: var(--avatar-size-sm);
|
|
49
|
+
--avatar-square-size: var(--avatar-size-sm);
|
|
50
|
+
--avatar-font-size: var(--avatar-font-size-sm);
|
|
51
|
+
--avatar-glyph-size: var(--avatar-glyph-size-sm);
|
|
52
|
+
--avatar-tinted-glyph-size: var(--avatar-glyph-size-sm);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ui-avatar[data-size="lg"] {
|
|
56
|
+
--avatar-size: var(--avatar-size-lg);
|
|
57
|
+
--avatar-square-size: var(--avatar-size-lg);
|
|
58
|
+
--avatar-font-size: var(--avatar-font-size-lg);
|
|
59
|
+
--avatar-glyph-size: var(--avatar-glyph-size-lg);
|
|
60
|
+
--avatar-tinted-glyph-size: var(--avatar-glyph-size-lg);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ui-avatar[data-size] svg {
|
|
64
|
+
inline-size: var(--avatar-glyph-size);
|
|
65
|
+
block-size: var(--avatar-glyph-size);
|
|
66
|
+
flex: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
39
69
|
.ui-avatar-image {
|
|
40
70
|
width: 100%;
|
|
41
71
|
height: 100%;
|
|
@@ -1066,8 +1096,8 @@
|
|
|
1066
1096
|
}
|
|
1067
1097
|
|
|
1068
1098
|
.ui-prose a {
|
|
1069
|
-
color: hsl(var(--primary));
|
|
1070
|
-
text-decoration:
|
|
1099
|
+
color: hsl(var(--prose-link-color, var(--primary)));
|
|
1100
|
+
text-decoration-line: var(--prose-link-decoration-line);
|
|
1071
1101
|
}
|
|
1072
1102
|
|
|
1073
1103
|
.ui-prose table {
|
|
@@ -199,6 +199,18 @@
|
|
|
199
199
|
flex-shrink: 0;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
.ui-upload-list-glyph {
|
|
203
|
+
display: flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
justify-content: center;
|
|
206
|
+
inline-size: var(--control-height-lg);
|
|
207
|
+
block-size: var(--control-height-lg);
|
|
208
|
+
border-radius: var(--radius);
|
|
209
|
+
background-color: hsl(var(--muted));
|
|
210
|
+
color: hsl(var(--muted-foreground));
|
|
211
|
+
flex-shrink: 0;
|
|
212
|
+
}
|
|
213
|
+
|
|
202
214
|
.ui-upload-picture-item {
|
|
203
215
|
inline-size: var(--upload-tile-size);
|
|
204
216
|
overflow-wrap: anywhere;
|
|
@@ -336,6 +348,11 @@
|
|
|
336
348
|
border-color: hsl(var(--primary));
|
|
337
349
|
}
|
|
338
350
|
|
|
351
|
+
.ui-upload-picture-empty-icon {
|
|
352
|
+
inline-size: var(--upload-picture-icon-size);
|
|
353
|
+
block-size: var(--upload-picture-icon-size);
|
|
354
|
+
}
|
|
355
|
+
|
|
339
356
|
.ui-upload-picture-empty-label {
|
|
340
357
|
margin-block-start: var(--upload-picture-empty-label-space-block-start);
|
|
341
358
|
font-size: var(--upload-picture-empty-label-font-size);
|
|
@@ -370,6 +387,11 @@
|
|
|
370
387
|
color: hsl(var(--muted-foreground));
|
|
371
388
|
}
|
|
372
389
|
|
|
390
|
+
.ui-upload-avatar-icon {
|
|
391
|
+
inline-size: var(--upload-avatar-icon-size);
|
|
392
|
+
block-size: var(--upload-avatar-icon-size);
|
|
393
|
+
}
|
|
394
|
+
|
|
373
395
|
.ui-upload-avatar-change {
|
|
374
396
|
position: absolute;
|
|
375
397
|
inset-inline: 0;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
@layer components {
|
|
3
|
+
svg.ui-icon[data-slot="icon"] {
|
|
4
|
+
inline-size: var(--icon-glyph-size);
|
|
5
|
+
block-size: var(--icon-glyph-size);
|
|
6
|
+
|
|
7
|
+
flex: 0 0 auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.ui-icon[data-size="2xs"] {
|
|
11
|
+
--icon-glyph-size: var(--icon-size-2xs);
|
|
12
|
+
}
|
|
13
|
+
.ui-icon[data-size="xs"] {
|
|
14
|
+
--icon-glyph-size: var(--icon-size-xs);
|
|
15
|
+
}
|
|
16
|
+
.ui-icon[data-size="sm"] {
|
|
17
|
+
--icon-glyph-size: var(--icon-size-sm);
|
|
18
|
+
}
|
|
19
|
+
.ui-icon[data-size="md"] {
|
|
20
|
+
--icon-glyph-size: var(--icon-size-md);
|
|
21
|
+
}
|
|
22
|
+
.ui-icon[data-size="lg"] {
|
|
23
|
+
--icon-glyph-size: var(--icon-size-lg);
|
|
24
|
+
}
|
|
25
|
+
.ui-icon[data-size="xl"] {
|
|
26
|
+
--icon-glyph-size: var(--icon-size-xl);
|
|
27
|
+
}
|
|
28
|
+
.ui-icon[data-size="2xl"] {
|
|
29
|
+
--icon-glyph-size: var(--icon-size-2xl);
|
|
30
|
+
}
|
|
31
|
+
.ui-icon[data-size="3xl"] {
|
|
32
|
+
--icon-glyph-size: var(--icon-size-3xl);
|
|
33
|
+
}
|
|
34
|
+
.ui-icon[data-size="4xl"] {
|
|
35
|
+
--icon-glyph-size: var(--icon-size-4xl);
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/styles/index.css
CHANGED
|
@@ -2083,6 +2083,16 @@
|
|
|
2083
2083
|
flex: 0 0 auto;
|
|
2084
2084
|
}
|
|
2085
2085
|
|
|
2086
|
+
.ui-topbar-item-icon {
|
|
2087
|
+
display: inline-flex;
|
|
2088
|
+
flex: 0 0 auto;
|
|
2089
|
+
align-items: center;
|
|
2090
|
+
}
|
|
2091
|
+
.ui-topbar-item-icon svg {
|
|
2092
|
+
inline-size: var(--topbar-icon-size);
|
|
2093
|
+
block-size: var(--topbar-icon-size);
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2086
2096
|
@media (width <= 68.75rem) {
|
|
2087
2097
|
.ui-topbar-center {
|
|
2088
2098
|
display: var(--topbar-center-compact-display);
|
|
@@ -51,37 +51,45 @@
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
[data-slot="text"][data-tone="default"],
|
|
54
|
-
[data-slot="heading"][data-tone="default"]
|
|
54
|
+
[data-slot="heading"][data-tone="default"],
|
|
55
|
+
[data-slot="icon"][data-tone="default"] {
|
|
55
56
|
color: hsl(var(--foreground));
|
|
56
57
|
}
|
|
57
58
|
[data-slot="text"][data-tone="muted"],
|
|
58
|
-
[data-slot="heading"][data-tone="muted"]
|
|
59
|
+
[data-slot="heading"][data-tone="muted"],
|
|
60
|
+
[data-slot="icon"][data-tone="muted"] {
|
|
59
61
|
color: hsl(var(--muted-foreground));
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
[data-slot="text"][data-tone="inherit"],
|
|
63
|
-
[data-slot="heading"][data-tone="inherit"]
|
|
65
|
+
[data-slot="heading"][data-tone="inherit"],
|
|
66
|
+
[data-slot="icon"][data-tone="inherit"] {
|
|
64
67
|
color: inherit;
|
|
65
68
|
}
|
|
66
69
|
[data-slot="text"][data-tone="primary"],
|
|
67
|
-
[data-slot="heading"][data-tone="primary"]
|
|
70
|
+
[data-slot="heading"][data-tone="primary"],
|
|
71
|
+
[data-slot="icon"][data-tone="primary"] {
|
|
68
72
|
color: hsl(var(--primary));
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
[data-slot="text"][data-tone="success"],
|
|
72
|
-
[data-slot="heading"][data-tone="success"]
|
|
76
|
+
[data-slot="heading"][data-tone="success"],
|
|
77
|
+
[data-slot="icon"][data-tone="success"] {
|
|
73
78
|
color: hsl(var(--text-success));
|
|
74
79
|
}
|
|
75
80
|
[data-slot="text"][data-tone="warning"],
|
|
76
|
-
[data-slot="heading"][data-tone="warning"]
|
|
81
|
+
[data-slot="heading"][data-tone="warning"],
|
|
82
|
+
[data-slot="icon"][data-tone="warning"] {
|
|
77
83
|
color: hsl(var(--text-warning));
|
|
78
84
|
}
|
|
79
85
|
[data-slot="text"][data-tone="destructive"],
|
|
80
|
-
[data-slot="heading"][data-tone="destructive"]
|
|
86
|
+
[data-slot="heading"][data-tone="destructive"],
|
|
87
|
+
[data-slot="icon"][data-tone="destructive"] {
|
|
81
88
|
color: hsl(var(--text-error));
|
|
82
89
|
}
|
|
83
90
|
[data-slot="text"][data-tone="info"],
|
|
84
|
-
[data-slot="heading"][data-tone="info"]
|
|
91
|
+
[data-slot="heading"][data-tone="info"],
|
|
92
|
+
[data-slot="icon"][data-tone="info"] {
|
|
85
93
|
color: hsl(var(--text-info));
|
|
86
94
|
}
|
|
87
95
|
|
|
@@ -166,6 +166,7 @@
|
|
|
166
166
|
--search-input-label-font-size: var(--font-size-xs);
|
|
167
167
|
--tag-input-chip-font-size: var(--font-size-xs);
|
|
168
168
|
--toggle-sm-font-size: var(--font-size-xs);
|
|
169
|
+
--toggle-xs-font-size: var(--font-size-xs);
|
|
169
170
|
--button-sm-font-size: var(--font-size-xs);
|
|
170
171
|
}
|
|
171
172
|
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
--prose-code-font-size: calc(1em / var(--font-size-ratio));
|
|
31
31
|
--prose-code-space-inline: var(--space-1);
|
|
32
32
|
--prose-code-radius: var(--radius-sm);
|
|
33
|
+
|
|
34
|
+
--prose-link-color: initial;
|
|
35
|
+
|
|
36
|
+
--prose-link-decoration-line: underline;
|
|
33
37
|
--prose-image-radius: var(--radius-md);
|
|
34
38
|
--timeline-note-font-size: var(--font-size-xs);
|
|
35
39
|
|
|
@@ -37,6 +41,28 @@
|
|
|
37
41
|
|
|
38
42
|
--avatar-tint: transparent;
|
|
39
43
|
|
|
44
|
+
--avatar-size: var(--control-height);
|
|
45
|
+
|
|
46
|
+
--avatar-size-xs: var(--control-height-xs);
|
|
47
|
+
|
|
48
|
+
--avatar-size-sm: var(--control-height-sm);
|
|
49
|
+
|
|
50
|
+
--avatar-size-lg: var(--control-height-lg);
|
|
51
|
+
|
|
52
|
+
--avatar-font-size: var(--font-size-base);
|
|
53
|
+
|
|
54
|
+
--avatar-font-size-xs: var(--font-size-2xs);
|
|
55
|
+
|
|
56
|
+
--avatar-font-size-sm: var(--font-size-xs);
|
|
57
|
+
|
|
58
|
+
--avatar-font-size-lg: var(--font-size-lg);
|
|
59
|
+
|
|
60
|
+
--avatar-glyph-size-xs: calc(var(--icon-size-xs) * var(--scaling));
|
|
61
|
+
|
|
62
|
+
--avatar-glyph-size-sm: calc(var(--icon-size-sm) * var(--scaling));
|
|
63
|
+
|
|
64
|
+
--avatar-glyph-size-lg: calc(var(--icon-size-lg) * var(--scaling));
|
|
65
|
+
|
|
40
66
|
--avatar-square-radius: var(--radius-lg);
|
|
41
67
|
--avatar-square-size: var(--control-height);
|
|
42
68
|
--avatar-square-background: initial;
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
--segmented-item-padding-inline: calc(var(--control-padding-x) - 1px);
|
|
13
13
|
|
|
14
|
+
--segmented-xs-font-size: var(--font-size-xs);
|
|
15
|
+
|
|
16
|
+
--segmented-xs-item-padding-inline: calc(var(--control-padding-x-compact) - 1px);
|
|
17
|
+
|
|
14
18
|
--segmented-item-gap: calc(var(--space-3) / 2);
|
|
15
19
|
|
|
16
20
|
--segmented-item-color: var(--muted-foreground);
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
--upload-picture-radius: var(--radius-md);
|
|
31
31
|
--upload-picture-preview-max-height: 12rem;
|
|
32
32
|
--upload-picture-empty-height: 8rem;
|
|
33
|
+
|
|
34
|
+
--upload-picture-icon-size: var(--icon-size-2xl);
|
|
33
35
|
--upload-picture-empty-label-space-block-start: var(--space-2);
|
|
34
36
|
--upload-picture-empty-label-font-size: var(--font-size-sm);
|
|
35
37
|
--upload-picture-overlay-font-size: var(--font-size-sm);
|
|
@@ -41,6 +43,8 @@
|
|
|
41
43
|
--upload-picture-badge-font-size: var(--font-size-xs);
|
|
42
44
|
|
|
43
45
|
--upload-avatar-size: 6rem;
|
|
46
|
+
|
|
47
|
+
--upload-avatar-icon-size: var(--icon-size-xl);
|
|
44
48
|
--upload-avatar-border-width: var(--stroke-md);
|
|
45
49
|
--upload-avatar-change-space-block: var(--space-1);
|
|
46
50
|
|
package/docs/CONSUMER-RULES.md
CHANGED
|
@@ -5,9 +5,9 @@ Read this once; the audit enforces it. Everything else in `docs/` is for contrib
|
|
|
5
5
|
1. Load styles with `@import "@godxjp/ui/styles"` (fonts bundled, 729 sliced woff2 faces, ~11.7 MB), `@import "@godxjp/ui/styles/core"` (no `@font-face` at all), `@import "@godxjp/ui/styles/core-with-fallbacks"` (`core` + six `local()`-only metric-matched faces, still zero network bytes — for when you supply Noto Sans JP yourself) or `@import "@godxjp/ui/styles/core-with-jis-level1"` (`core-with-fallbacks` + Noto Sans JP merged to JIS X 0208 level 1: **3 requests, ~1.53 MB, once** instead of ~8 font requests on every navigation — for a Japanese app that wants the bundled face). Never cherry-pick `*-layout.css`.
|
|
6
6
|
2. Every page is `<PageContainer title subtitle extra footer>`; its sections are spaced by the page. Group items inside a section with `<Flex direction="col" gap>` or `<ResponsiveGrid>`.
|
|
7
7
|
3. No Tailwind layout on your own elements: no `flex`, `grid`, `gap-*`, `p-*`, `m-*`, `space-*`. Rows are `<Flex>` (default row), stacks are `<Flex direction="col">`, grids are `<ResponsiveGrid>`.
|
|
8
|
-
4. No hand-rolled surfaces: no `rounded-* border bg-*` divs. A box is `Card`, a pill is `Badge`, a person is `Avatar`, a row is `ListRow`, a label/value pair is `Descriptions`, an empty area is `EmptyState`, a read-only sample of a colour the USER chose is `Swatch`.
|
|
8
|
+
4. No hand-rolled surfaces: no `rounded-* border bg-*` divs. A box is `Card`, a pill is `Badge`, a person is `Avatar`, a row is `ListRow`, a label/value pair is `Descriptions`, an empty area is `EmptyState`, a read-only sample of a colour the USER chose is `Swatch`. A LIST of those rows is `<Flex as="ul" marker="none" direction="col" gap="none">` with `<ListRow as="li">` children — `marker="none"` keeps the `<ul>`, the `<li>` semantics and the gap token while dropping the bullet and the indent. Never a raw `<ul>`/`<ol>` (it carries no gap token), never `<div role="list">` + `<div role="listitem">`, and never a wrapper around each row: the divider is `:not(:last-child)` among siblings, so a row alone in its own wrapper is always the last one and EVERY divider disappears silently. A bulleted prose list is the same `<Flex as="ul">` without `marker`.
|
|
9
9
|
5. Real controls only: `Button`, `Input`, `Select`, `Textarea`, `Checkbox`… never raw `<button>`/`<input>`; a labelled control lives in `<FormField label>`. A Select outside a form takes `width="auto"`. **A disabled control's reason is visible text, never a tooltip** — see below.
|
|
10
|
-
6. Text is `<Text>` / `<Heading>` with `tone`, `size`, `weight`, `truncate`, `mono` — not `className="text-muted-foreground font-semibold"`.
|
|
10
|
+
6. Text is `<Text>` / `<Heading>` with `tone`, `size`, `weight`, `truncate`, `mono` — not `className="text-muted-foreground font-semibold"`. A STANDALONE glyph is `<Icon as={Lock} size="sm" tone="muted" />` from `@godxjp/ui/general`: a bare lucide icon carries its own `width="24" height="24"` and only four places re-size it for you (`Button`, a `DropdownMenuItem`, a `TopbarItem`, a `ListRow` leading slot), so everywhere else — in a `Text`, a table cell, an `<a>` — it draws at 24px beside 14px type. `size-4` and `w-[16px]` are closed to you by rules 3 and 8, and `size={16}` hard-codes a number the theme owns; `Icon` puts the glyph on the `--icon-size-*` scale (`2xs…4xl`) instead, and is `aria-hidden` unless you give it a `label` (then it is `role="img"` with that name). The audit rule is `lucide-icon-needs-size`.
|
|
11
11
|
7. Colours are semantic tokens (`tone="destructive"`, `bg-primary`), never palette names, hex, or `bg-black` / `text-white`.
|
|
12
12
|
8. Sizes come from props (`size`, `width`, `columns`), never `w-[240px]` / `max-h-[420px]`.
|
|
13
13
|
9. Logical directions (`ms-`, `me-`, `start-`, `end-`) when a utility is unavoidable; never `ml-` / `left-`.
|
package/docs/CUSTOMER-THEMING.md
CHANGED
|
@@ -213,6 +213,32 @@ Density (`<PageContainer density>`) scales component sizes, not the grid. - **Pi
|
|
|
213
213
|
|
|
214
214
|
---
|
|
215
215
|
|
|
216
|
+
## Selectors the package promises are YOURS
|
|
217
|
+
|
|
218
|
+
A `data-*` attribute the package never writes is a selector you can hold a stylesheet against — the one place where CSS of your own is the documented route rather than a workaround. Each of these is a promise held by a test, not an accident of the current markup:
|
|
219
|
+
|
|
220
|
+
| You write | The package promises | Why it exists |
|
|
221
|
+
| --- | --- | --- |
|
|
222
|
+
| `.ui-prose a[data-…]` | Prose writes `data-*` on its **own root only** — never on a descendant. Every `data-*` on an `a` inside it is yours, survives the render, and stays selectable (gh#717) | A renderer knows things about a link that the package cannot: in a wiki, a link whose target **does not exist yet** must read differently from one that resolves |
|
|
223
|
+
| `<TableRow data-expanded-row="">` | The striping counts records, not DOM rows — a row you mark is skipped in the count and wears its record's stripe | A detail row under a record is your composition, not a row of data |
|
|
224
|
+
| `[data-tenant]`, `[data-program]` | Every anchor token re-resolves at the scope (below) | One app, many brands |
|
|
225
|
+
|
|
226
|
+
**Style a marked link through the knob, not around it.** `--prose-link-color` is read as `hsl(var(--prose-link-color, var(--primary)))` **at the anchor**, so declaring the custom property inside your own higher-specificity selector is enough — you never have to restate the `color` declaration, and a later package change to how the ink is painted still reaches you:
|
|
227
|
+
|
|
228
|
+
```css
|
|
229
|
+
/* your app's stylesheet */
|
|
230
|
+
.ui-prose a[data-unresolved="true"] {
|
|
231
|
+
--prose-link-color: var(--text-error); /* the TEXT tier — 7.25:1 light, 5.51:1 dark on a card */
|
|
232
|
+
text-decoration-style: dashed;
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Use `--text-error`, not `--destructive`: the fill tier is tuned for a white label on top of it and measures 2.95:1 as ink on the dark card (gh#610). The whole family is `--prose-link-color` (default `hsl(var(--primary))`, resolved at the anchor so a scoped re-tint reaches it) and `--prose-link-decoration-line` (default `underline`). Set the first on `[data-tenant]` to re-tint every wiki link at once.
|
|
237
|
+
|
|
238
|
+
There is **no prop** naming the attribute, deliberately: the attribute IS the API, the same way `data-expanded-row` and `data-axe-open` are. A prop would make the package own a name only your renderer knows, and would let exactly one state be marked.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
216
242
|
## Multi-tenant (one app, many brands)
|
|
217
243
|
|
|
218
244
|
Scope the overrides under a tenant attribute instead of `:root`. The colour utilities are declared with `@theme inline`, so a scoped `--primary` (and the other anchors) **re-resolve at the element** — `bg-primary`, `text-success`, every component surface, the focus ring, the brand glow, gradients and the modal scrim all retint inside the scope:
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
> Generated by `scripts/frame-coverage.mjs` (issue #163). Do not edit by hand — run `pnpm check:frame-coverage`.
|
|
4
4
|
> Standard: [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md). A missing dimension is **UNTESTED**, never a pass.
|
|
5
5
|
|
|
6
|
-
- Public components: **
|
|
7
|
-
- With ≥1 frame: **
|
|
6
|
+
- Public components: **164**
|
|
7
|
+
- With ≥1 frame: **143** · zero-frame: **21**
|
|
8
8
|
- Fully covered (every contract axis declared): **0**
|
|
9
9
|
|
|
10
10
|
## UNTESTED — no `/frame/**` route
|
|
@@ -74,6 +74,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
74
74
|
| Logo | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
75
75
|
| Reveal | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
76
76
|
| Activity | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
77
|
+
| Icon | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
77
78
|
| DataTable | ✓ | ✓ | · | · | · | · | · | · | · | · |
|
|
78
79
|
| Card | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
79
80
|
| CardContent | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|