@bspk/ui 1.3.19 → 1.3.20

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 (105) hide show
  1. package/dist/components/Accordion/AccordionExample.js +1 -1
  2. package/dist/components/Accordion/AccordionExample.js.map +1 -1
  3. package/dist/components/BannerAlert/BannerAlert.js +1 -1
  4. package/dist/components/BannerAlert/BannerAlert.js.map +1 -1
  5. package/dist/components/BannerAlert/banner-alert.css +3 -3
  6. package/dist/components/BannerAlert/banner-alert.css.js +3 -3
  7. package/dist/components/CheckboxOption/CheckboxOption.d.ts +15 -3
  8. package/dist/components/CheckboxOption/CheckboxOption.js +2 -3
  9. package/dist/components/CheckboxOption/CheckboxOption.js.map +1 -1
  10. package/dist/components/Dialog/Dialog.d.ts +17 -7
  11. package/dist/components/Dialog/Dialog.js +19 -11
  12. package/dist/components/Dialog/Dialog.js.map +1 -1
  13. package/dist/components/Dialog/DialogExample.d.ts +2 -2
  14. package/dist/components/Dialog/DialogExample.js +32 -3
  15. package/dist/components/Dialog/DialogExample.js.map +1 -1
  16. package/dist/components/Dialog/dialog.css +74 -4
  17. package/dist/components/Dialog/dialog.css.js +74 -4
  18. package/dist/components/Flex/Flex.d.ts +2 -0
  19. package/dist/components/Flex/Flex.js +1 -0
  20. package/dist/components/Flex/Flex.js.map +1 -1
  21. package/dist/components/ListItem/list-item.css +4 -0
  22. package/dist/components/ListItem/list-item.css.js +4 -0
  23. package/dist/components/Modal/Modal.js +1 -2
  24. package/dist/components/Modal/Modal.js.map +1 -1
  25. package/dist/components/Modal/modal.css +4 -0
  26. package/dist/components/Modal/modal.css.js +4 -0
  27. package/dist/components/PageHeader/PageHeader.d.ts +1 -1
  28. package/dist/components/PageHeader/PageHeader.js +1 -1
  29. package/dist/components/PageHeader/PageHeaderBlockConfigs.d.ts +1 -0
  30. package/dist/components/PageHeader/PageHeaderBlockConfigs.js +32 -0
  31. package/dist/components/PageHeader/PageHeaderBlockConfigs.js.map +1 -0
  32. package/dist/components/PageHeader/PageHeaderExample.d.ts +3 -2
  33. package/dist/components/PageHeader/PageHeaderExample.js +4 -42
  34. package/dist/components/PageHeader/PageHeaderExample.js.map +1 -1
  35. package/dist/components/PageHeader/page-header.css +1 -1
  36. package/dist/components/PageHeader/page-header.css.js +1 -1
  37. package/dist/components/Portal/Portal.d.ts +1 -1
  38. package/dist/components/RadioOption/RadioOption.d.ts +7 -3
  39. package/dist/components/RadioOption/RadioOption.js +2 -3
  40. package/dist/components/RadioOption/RadioOption.js.map +1 -1
  41. package/dist/components/Scrim/Scrim.d.ts +3 -1
  42. package/dist/components/Scrim/Scrim.js +2 -2
  43. package/dist/components/Scrim/Scrim.js.map +1 -1
  44. package/dist/components/Scrim/scrim.css +3 -0
  45. package/dist/components/Scrim/scrim.css.js +3 -0
  46. package/dist/components/SwitchOption/SwitchOption.d.ts +16 -3
  47. package/dist/components/SwitchOption/SwitchOption.js +3 -4
  48. package/dist/components/SwitchOption/SwitchOption.js.map +1 -1
  49. package/dist/components/Tag/Tag.d.ts +2 -1
  50. package/dist/components/Tag/Tag.js +2 -2
  51. package/dist/components/Tag/Tag.js.map +1 -1
  52. package/dist/styles/base.css +0 -42
  53. package/dist/styles/base.css.js +0 -42
  54. package/dist/types/meta.d.ts +6 -0
  55. package/dist/types/meta.js.map +1 -1
  56. package/dist/utils/blocks.d.ts +32 -0
  57. package/dist/utils/blocks.js +21 -0
  58. package/dist/utils/blocks.js.map +1 -0
  59. package/dist/utils/demo.d.ts +33 -9
  60. package/dist/utils/demo.js +98 -0
  61. package/dist/utils/demo.js.map +1 -1
  62. package/meta.ts +39 -1
  63. package/package.json +1 -3
  64. package/src/components/Accordion/AccordionExample.tsx +1 -1
  65. package/src/components/BannerAlert/BannerAlert.tsx +2 -2
  66. package/src/components/BannerAlert/banner-alert.scss +1 -1
  67. package/src/components/CheckboxOption/CheckboxOption.tsx +26 -14
  68. package/src/components/Dialog/Dialog.tsx +20 -10
  69. package/src/components/Dialog/DialogExample.tsx +104 -6
  70. package/src/components/Dialog/dialog.scss +91 -4
  71. package/src/components/Flex/Flex.tsx +3 -0
  72. package/src/components/ListItem/list-item.scss +4 -0
  73. package/src/components/Modal/Modal.tsx +1 -4
  74. package/src/components/Modal/modal.scss +5 -0
  75. package/src/components/PageHeader/PageHeader.rtl.test.tsx +8 -5
  76. package/src/components/PageHeader/PageHeader.tsx +1 -1
  77. package/src/components/PageHeader/PageHeaderBlockConfigs.tsx +152 -0
  78. package/src/components/PageHeader/PageHeaderExample.tsx +6 -44
  79. package/src/components/PageHeader/page-header.scss +1 -1
  80. package/src/components/Portal/Portal.tsx +1 -1
  81. package/src/components/RadioOption/RadioOption.tsx +16 -8
  82. package/src/components/Scrim/Scrim.tsx +4 -1
  83. package/src/components/Scrim/scrim.scss +4 -0
  84. package/src/components/SwitchOption/SwitchOption.tsx +28 -9
  85. package/src/components/Tag/Tag.tsx +9 -2
  86. package/src/styles/base.scss +0 -52
  87. package/src/types/meta.ts +7 -0
  88. package/src/utils/blocks.ts +26 -0
  89. package/src/utils/demo.ts +141 -18
  90. package/dist/components/Drawer/Drawer.d.ts +0 -73
  91. package/dist/components/Drawer/Drawer.js +0 -46
  92. package/dist/components/Drawer/Drawer.js.map +0 -1
  93. package/dist/components/Drawer/DrawerExample.d.ts +0 -5
  94. package/dist/components/Drawer/DrawerExample.js +0 -53
  95. package/dist/components/Drawer/DrawerExample.js.map +0 -1
  96. package/dist/components/Drawer/drawer.css +0 -62
  97. package/dist/components/Drawer/drawer.css.js +0 -67
  98. package/dist/components/Drawer/index.d.ts +0 -1
  99. package/dist/components/Drawer/index.js +0 -2
  100. package/dist/components/Drawer/index.js.map +0 -1
  101. package/src/components/Drawer/Drawer.rtl.test.tsx +0 -27
  102. package/src/components/Drawer/Drawer.tsx +0 -127
  103. package/src/components/Drawer/DrawerExample.tsx +0 -117
  104. package/src/components/Drawer/drawer.scss +0 -74
  105. package/src/components/Drawer/index.tsx +0 -1
@@ -1,6 +1,6 @@
1
1
  import { CSSProperties, ReactNode } from 'react';
2
2
  import { AlertVariant, DataProps } from '-/types/common';
3
- import { ComponentMeta, TypeProperty } from '-/types/meta';
3
+ import { BlockConfig, ComponentMeta, TypeProperty } from '-/types/meta';
4
4
  export type DemoAction = (message: string, variant?: AlertVariant) => void;
5
5
  export type DemoSetState<Props = Record<string, unknown>> = (next: Partial<Props> | ((prev: Props) => Partial<Props>)) => void;
6
6
  export type TypePropertyDemo = Omit<TypeProperty, 'example'> & {
@@ -32,11 +32,13 @@ export type ComponentVariantOverride<Props> = {
32
32
  };
33
33
  };
34
34
  export type ComponentPageSection<Props = Record<string, unknown>> = {
35
- title: string;
36
- content: (params: {
35
+ title?: string;
36
+ description?: string;
37
+ content?: (params: {
37
38
  Component?: React.ComponentType<Props>;
38
39
  props: Props;
39
40
  CodeExample: CodeExample;
41
+ CodePlayground: CodePlayground;
40
42
  Syntax: Syntax;
41
43
  }) => React.ReactNode;
42
44
  location?: 'afterDemo' | 'beforeDemo';
@@ -44,7 +46,7 @@ export type ComponentPageSection<Props = Record<string, unknown>> = {
44
46
  export type ComponentVariantOverrides<Props = Record<string, unknown>, PropName extends keyof Props = keyof Props> = {
45
47
  [Key in PropName]?: ComponentVariantOverride<Props> | false;
46
48
  };
47
- export type ComponentExample<Props = Record<string, unknown>, PropName extends keyof Props = keyof Props> = {
49
+ export type ComponentExample<Props extends Record<string, unknown> = Record<string, unknown>, PropName extends keyof Props = keyof Props> = {
48
50
  /**
49
51
  * The style of the wrapping component.
50
52
  *
@@ -100,6 +102,14 @@ export type ComponentExample<Props = Record<string, unknown>, PropName extends k
100
102
  * @default false
101
103
  */
102
104
  hideDemo?: boolean;
105
+ /**
106
+ * Hide the usage section entirely.
107
+ *
108
+ * @default false
109
+ */
110
+ hideUsage?: boolean;
111
+ /** Block Configs */
112
+ blockConfigs?: BlockConfig[];
103
113
  };
104
114
  export type Syntax = (params: {
105
115
  code: string;
@@ -107,7 +117,7 @@ export type Syntax = (params: {
107
117
  style?: CSSProperties;
108
118
  pretty?: boolean;
109
119
  }) => React.ReactNode;
110
- export type CodeExample = (params: DataProps & {
120
+ export type CodeExample = (params: DataProps & any & {
111
121
  containerStyle?: CSSProperties;
112
122
  children: ReactNode;
113
123
  accessibility?: boolean;
@@ -115,9 +125,15 @@ export type CodeExample = (params: DataProps & {
115
125
  language?: PrettyParser | undefined;
116
126
  str: string;
117
127
  };
118
- }) => React.ReactNode;
128
+ style?: CSSProperties;
129
+ }) => JSX.Element;
130
+ export type CodePlaygroundProps = {
131
+ defaultCode: string;
132
+ defaultShowCode?: boolean;
133
+ };
134
+ export type CodePlayground = (params: CodePlaygroundProps) => JSX.Element;
119
135
  export type PrettyParser = 'css' | 'estree' | 'html' | 'scss' | 'typescript';
120
- export type ComponentExampleFn<Props = Record<string, unknown>> = (params: {
136
+ export type ComponentExampleFn<Props extends Record<string, unknown> = Record<string, unknown>> = (params: {
121
137
  setState: DemoSetState<Props>;
122
138
  action: DemoAction;
123
139
  componentsMeta: ComponentMeta[];
@@ -134,13 +150,21 @@ export type Preset<Props> = {
134
150
  /** The props of the component. This is used to set props of the component. These values can't be changed in the UI. */
135
151
  propState: Omit<Props, OnHandlers> & Record<OnHandlers, unknown>;
136
152
  /**
137
- * Hide the demo for this preset.
153
+ * Hide the demo option for this preset.
138
154
  *
139
155
  * @default false
140
156
  */
141
- hideDemo?: boolean;
157
+ hideDemoOption?: boolean;
158
+ /** Hide the playground for this preset. */
159
+ hidePlayground?: boolean;
160
+ /** Preset used for block examples. */
161
+ block?: boolean;
142
162
  };
143
163
  export type DemoPreset<P = Record<string, unknown>> = Preset<P> & {
144
164
  value: string;
145
165
  };
146
166
  export declare function createUid(prefix?: string): string;
167
+ export declare function reactElementToString(element: React.ReactElement): string;
168
+ export declare function componentToString<Props extends Record<string, any> = Record<string, any>>(componentName: string, propState: Props, propsMeta?: TypePropertyDemo[]): string;
169
+ export declare function kebabCase(str: string): string;
170
+ export declare function convertReactToCodeString(element: React.ReactElement): string;
@@ -1,4 +1,102 @@
1
+ import { isValidElement } from 'react';
1
2
  export function createUid(prefix = 'uid') {
2
3
  return `${prefix}-${Math.random().toString(36).substring(2, 9)}`;
3
4
  }
5
+ export function reactElementToString(element) {
6
+ if (!isReactElement(element))
7
+ return '';
8
+ const subComponentName = typeof element.type === 'string' ? element.type : element.type.name || 'Component';
9
+ return componentToString(subComponentName, element.props);
10
+ }
11
+ export function componentToString(componentName, propState, propsMeta) {
12
+ const propsString = Object.entries(propState)
13
+ .map(([key, value]) => {
14
+ const propMeta = propsMeta?.find((prop) => prop.name === key);
15
+ let formattedValue;
16
+ if (typeof value === 'string') {
17
+ formattedValue = `"${value}"`;
18
+ if (propMeta?.type === 'BspkIcon')
19
+ formattedValue = `{<Svg${value} />}`;
20
+ }
21
+ else if (typeof value === 'boolean' || typeof value === 'number') {
22
+ formattedValue = `{${value}}`;
23
+ }
24
+ else if (isReactElement(value)) {
25
+ const subComponentName = typeof value.type === 'string' ? value.type : value.type.name || 'Component';
26
+ formattedValue = `{${componentToString(subComponentName, value.props)}}`;
27
+ }
28
+ else if (Array.isArray(value)) {
29
+ return ` ${key}={[${value
30
+ .map((item) => (isValidElement(item) ? convertReactToCodeString(item) : '...')) // Simplified for brevity
31
+ .join(', ')}]}`;
32
+ }
33
+ else if (typeof value === 'object') {
34
+ formattedValue = `{${JSON.stringify(value, null, 2)}}`;
35
+ }
36
+ else if (value === null) {
37
+ formattedValue = '{null}';
38
+ }
39
+ else if (value === undefined) {
40
+ return ''; // skip undefined props
41
+ }
42
+ else {
43
+ formattedValue = `{${value.toString()}}`;
44
+ }
45
+ return ` ${key}=${formattedValue}`;
46
+ })
47
+ .filter(Boolean)
48
+ .join('\n');
49
+ return `<${componentName}\n${propsString}\n/>`;
50
+ }
51
+ function isReactElement(value) {
52
+ return (typeof value === 'object' &&
53
+ value !== null &&
54
+ (value.$$typeof === Symbol.for('react.element') ||
55
+ (value.type && (typeof value.type === 'string' || typeof value.type === 'function'))));
56
+ }
57
+ export function kebabCase(str) {
58
+ return (str
59
+ .normalize('NFD') // Normalize to decompose accents
60
+ .replace(/[\u0300-\u036f&()']/g, '') // Remove accents
61
+ // Handle camelCase by inserting hyphens between lowercase and uppercase
62
+ .replace(/([a-zA-Z])([A-Z][a-z])/g, '$1-$2')
63
+ // do it again for the next uppercase letter
64
+ .replace(/([a-zA-Z])([A-Z][a-z])/g, '$1-$2')
65
+ .replace(/[^a-zA-Z0-9]+/g, '-') // Replace non-alphanumeric characters with hyphens
66
+ .replace(/^-+|-+$/g, '') // Trim leading or trailing hyphens
67
+ .replace(/--+/g, '-') // Replace multiple hyphens with a single hyphen
68
+ .toLowerCase()); // Convert to lowercase
69
+ }
70
+ export function convertReactToCodeString(element) {
71
+ return `<${element.type}${Object.entries(element.props)
72
+ .map(([key, value]) => {
73
+ if (typeof value === 'string') {
74
+ return ` ${key}="${value}"`;
75
+ }
76
+ else if (typeof value === 'number' || typeof value === 'boolean') {
77
+ return ` ${key}={${value}}`;
78
+ }
79
+ else if (typeof value === 'function') {
80
+ return ` ${key}={() => {}}`;
81
+ }
82
+ else if (isValidElement(value)) {
83
+ return ` ${key}={${convertReactToCodeString(value)}}`;
84
+ }
85
+ else if (Array.isArray(value)) {
86
+ return ` ${key}={[${value
87
+ .map((item) => (isValidElement(item) ? convertReactToCodeString(item) : '...')) // Simplified for brevity
88
+ .join(', ')}]}`;
89
+ }
90
+ else if (value === null) {
91
+ return ` ${key}={null}`;
92
+ }
93
+ else if (value === undefined) {
94
+ return ` ${key}={undefined}`;
95
+ }
96
+ else {
97
+ return ` ${key}={${JSON.stringify(value)}}`;
98
+ }
99
+ })
100
+ .join('')}>${element.props.children ? '...' : ''}</${element.type}>`;
101
+ }
4
102
  //# sourceMappingURL=demo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"demo.js","sourceRoot":"","sources":["../../src/utils/demo.ts"],"names":[],"mappings":"AA6KA,MAAM,UAAU,SAAS,CAAC,SAAiB,KAAK;IAC5C,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACrE,CAAC"}
1
+ {"version":3,"file":"demo.js","sourceRoot":"","sources":["../../src/utils/demo.ts"],"names":[],"mappings":"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"}
package/meta.ts CHANGED
@@ -14,7 +14,7 @@ import { fileURLToPath } from 'url';
14
14
 
15
15
  import * as TJS from 'typescript-json-schema';
16
16
 
17
- import { ComponentMeta, TypeProperty, UtilityMeta, TypeMeta, ComponentPhase } from './src/types/meta';
17
+ import { ComponentMeta, TypeProperty, UtilityMeta, TypeMeta, ComponentPhase, BlockConfig } from './src/types/meta';
18
18
 
19
19
  const COMPONENT_PHASE_ORDER: ComponentPhase[] = [
20
20
  'Utility', // Utility components are not tracked in the progress
@@ -201,6 +201,15 @@ function generateComponentMeta({
201
201
  }
202
202
  : undefined;
203
203
 
204
+ const blockFilePath =
205
+ //
206
+ path.join(srcDir, 'components', name, `${name}BlockConfigs.tsx`);
207
+
208
+ let blockConfigs: BlockConfig[] | undefined;
209
+ if (fs.existsSync(blockFilePath)) {
210
+ blockConfigs = generateBlocksMeta(blockFilePath);
211
+ }
212
+
204
213
  return {
205
214
  description: componentDoc.description,
206
215
  file: componentFile.split(srcDir)[1],
@@ -214,6 +223,7 @@ function generateComponentMeta({
214
223
  ? componentDoc.phase
215
224
  : 'Backlog') as ComponentPhase,
216
225
  generated: 'generated' in componentDoc,
226
+ blockConfigs,
217
227
  } as ComponentMeta;
218
228
  }
219
229
 
@@ -608,6 +618,34 @@ async function main() {
608
618
  process.exit(0);
609
619
  }
610
620
 
621
+ function generateBlocksMeta(blockFilePath: string) {
622
+ const blockFileContent = fs.readFileSync(path.resolve(blockFilePath), 'utf-8');
623
+
624
+ const exampleContent = blockFileContent.matchAll(/<BlockExample\s([\s\S]*?)<\/BlockExample>/g);
625
+
626
+ const blocks: BlockConfig[] = [...exampleContent].map((match) => {
627
+ const blockString = match[1];
628
+
629
+ const nameMatch = blockString.match(/name=["|'](.*?)["|']/);
630
+ const name = nameMatch ? nameMatch[1] : 'Unnamed Block';
631
+
632
+ const componentMatch = blockString.match(
633
+ /<BlockExample\.Component>\s*([\s\S]*?)\s*<\/BlockExample\.Component>/,
634
+ );
635
+ const component = componentMatch ? componentMatch[1].trim() : '';
636
+
637
+ const patternMatch = blockString.match(/<BlockExample\.Pattern>\s*([\s\S]*?)\s*<\/BlockExample\.Pattern>/);
638
+ const pattern = patternMatch ? patternMatch[1].trim() : '';
639
+
640
+ return {
641
+ name,
642
+ component,
643
+ pattern,
644
+ };
645
+ });
646
+
647
+ return blocks;
648
+ }
611
649
  main();
612
650
 
613
651
  /** Copyright 2025 Anywhere Real Estate - CC BY 4.0 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bspk/ui",
3
- "version": "1.3.19",
3
+ "version": "1.3.20",
4
4
  "license": "CC-BY-4.0",
5
5
  "type": "module",
6
6
  "files": [
@@ -93,8 +93,6 @@
93
93
  "./Dialog/*": "./dist/components/Dialog/*.js",
94
94
  "./Divider": "./dist/components/Divider/index.js",
95
95
  "./Divider/*": "./dist/components/Divider/*.js",
96
- "./Drawer": "./dist/components/Drawer/index.js",
97
- "./Drawer/*": "./dist/components/Drawer/*.js",
98
96
  "./EmptyState": "./dist/components/EmptyState/index.js",
99
97
  "./EmptyState/*": "./dist/components/EmptyState/*.js",
100
98
  "./ExamplePlaceholder": "./dist/components/ExamplePlaceholder/index.js",
@@ -51,7 +51,7 @@ export const presets: Preset<AccordionProps>[] = [
51
51
  },
52
52
  {
53
53
  label: '1 disabled and open (but not showing)',
54
- hideDemo: true,
54
+ hideDemoOption: true,
55
55
  propState: {
56
56
  items: [
57
57
  {
@@ -94,7 +94,7 @@ export function BannerAlert({
94
94
  </div>
95
95
  <div data-content>
96
96
  {(header || onClose) && (
97
- <header>
97
+ <div data-header>
98
98
  <span>{header}</span>
99
99
  {typeof onClose === 'function' && (
100
100
  <Button
@@ -106,7 +106,7 @@ export function BannerAlert({
106
106
  variant="tertiary"
107
107
  />
108
108
  )}
109
- </header>
109
+ </div>
110
110
  )}
111
111
  <div data-body>
112
112
  <span>{body}</span>
@@ -46,7 +46,7 @@
46
46
  flex-direction: column;
47
47
  padding: var(--spacing-sizing-02) var(--spacing-sizing-02) var(--spacing-sizing-02) var(--spacing-sizing-04);
48
48
 
49
- header {
49
+ [data-header] {
50
50
  display: flex;
51
51
  flex-direction: row;
52
52
  gap: var(--spacing-sizing-03);
@@ -1,8 +1,22 @@
1
1
  import { CheckboxProps, Checkbox } from '-/components/Checkbox';
2
- import { ToggleOption, ToggleOptionControlProps } from '-/components/ToggleOption';
2
+ import { ListItem } from '-/components/ListItem';
3
3
  import { CommonProps } from '-/types/common';
4
4
 
5
- export type CheckboxOptionProps = CommonProps<'style'> & ToggleOptionControlProps<CheckboxProps>;
5
+ export type CheckboxOptionProps = CheckboxProps &
6
+ CommonProps<'style'> & {
7
+ /**
8
+ * The label of the option. Also used as the aria-label of the control.
9
+ *
10
+ * @required
11
+ */
12
+ label: string;
13
+ /**
14
+ * The description of the option.
15
+ *
16
+ * @type multiline
17
+ */
18
+ description?: string;
19
+ };
6
20
 
7
21
  /**
8
22
  * A control that allows users to choose one or more items from a list or turn an feature on or off.
@@ -39,20 +53,18 @@ export function CheckboxOption({
39
53
  style,
40
54
  ...checkboxProps
41
55
  }: CheckboxOptionProps) {
42
- const label = labelProp || description;
43
56
  const ariaLabel = description ? `${labelProp} - ${description}` : labelProp;
44
57
  return (
45
- label && (
46
- <ToggleOption
47
- data-bspk="checkbox-option"
48
- description={description}
49
- disabled={disabled}
50
- label={label}
51
- style={style}
52
- >
53
- <Checkbox {...checkboxProps} aria-label={ariaLabel} disabled={disabled} />
54
- </ToggleOption>
55
- )
58
+ <ListItem
59
+ aria-disabled={disabled || undefined}
60
+ as="label"
61
+ label={labelProp}
62
+ leading={<Checkbox {...checkboxProps} aria-label={ariaLabel} disabled={disabled} />}
63
+ owner="checkbox-option"
64
+ style={style}
65
+ subText={description}
66
+ width="hug"
67
+ />
56
68
  );
57
69
  }
58
70
 
@@ -54,11 +54,12 @@ export type DialogProps = CommonProps<'id' | 'owner'> &
54
54
  };
55
55
 
56
56
  /**
57
- * Dialogs display important information that users need to acknowledge. They appear over the interface and block
57
+ * Dialogs display important information that users need to acknowledge. They appear over the interface and may block
58
58
  * further interactions until an action is selected.
59
59
  *
60
- * This is a low-level component that provides the container and functionality for dialogs. You will typically want to
61
- * use a higher-level component that provides a consistent UI and behavior for dialogs such as Modal.
60
+ * The Modal component is a higher-level component built on top of Dialog that includes standard dialog UI and behavior.
61
+ *
62
+ * Also known as: Tray, Drawer, Flyout, Sheet
62
63
  *
63
64
  * @example
64
65
  * import { Dialog } from '@bspk/ui/Dialog';
@@ -70,11 +71,20 @@ export type DialogProps = CommonProps<'id' | 'owner'> &
70
71
  * return (
71
72
  * <>
72
73
  * <Button label="Open Dialog" onClick={() => setOpen(true)} />
73
- * <Dialog open={open} onClose={() => setOpen(false)}>
74
+ * <Dialog onClose={() => setOpen(false)} open={open}>
74
75
  * <div style={{ padding: 'var(--spacing-sizing-04)' }}>
75
- * <h1>Dialog Title</h1>
76
+ * <Flex align="center" justify="space-between">
77
+ * <h4>Dialog Title</h4>
78
+ * <Button
79
+ * icon={<SvgClose />}
80
+ * iconOnly
81
+ * label="Close dialog"
82
+ * onClick={() => setOpen(false)}
83
+ * variant="tertiary"
84
+ * />
85
+ * </Flex>
76
86
  * <p>This is the content of the dialog.</p>
77
- * <Button label="Cancel" variant="secondary" onClick={() => setOpen(false)} />
87
+ * <Button label="Cancel" onClick={() => setOpen(false)} variant="secondary" />
78
88
  * </div>
79
89
  * </Dialog>
80
90
  * </>
@@ -82,7 +92,7 @@ export type DialogProps = CommonProps<'id' | 'owner'> &
82
92
  * };
83
93
  *
84
94
  * @name Dialog
85
- * @phase Utility
95
+ * @phase Stable
86
96
  */
87
97
  export function Dialog({
88
98
  children,
@@ -119,6 +129,7 @@ export function Dialog({
119
129
  {...containerProps}
120
130
  data-bspk="dialog"
121
131
  data-bspk-owner={owner || undefined}
132
+ data-contained={!!container || undefined}
122
133
  data-placement={placement}
123
134
  id={id}
124
135
  ref={innerRef}
@@ -144,9 +155,8 @@ export function Dialog({
144
155
  </FocusTrap>
145
156
  </div>
146
157
  <Scrim
147
- onClick={() => {
148
- onClose();
149
- }}
158
+ contained={!!container || undefined}
159
+ onClick={() => onClose()}
150
160
  owner="dialog"
151
161
  visible={showScrim !== false}
152
162
  />
@@ -1,8 +1,9 @@
1
- import { DialogProps } from '.';
1
+ import { SvgClose } from '@bspk/icons/Close';
2
+ import { useRef, useState } from 'react';
3
+ import { Dialog, DialogProps } from '.';
2
4
  import { Button } from '-/components/Button';
3
- import { ComponentExample, Preset } from '-/utils/demo';
4
-
5
- export const presets: Preset<DialogProps>[] = [];
5
+ import { Flex } from '-/components/Flex';
6
+ import { ComponentExample } from '-/utils/demo';
6
7
 
7
8
  export const DialogExample: ComponentExample<DialogProps> = {
8
9
  render: ({ props, setState, Component }) => {
@@ -11,11 +12,108 @@ export const DialogExample: ComponentExample<DialogProps> = {
11
12
  <>
12
13
  <Button label={label} onClick={() => setState({ open: true })} />
13
14
  <Component data-example-component {...props} id="exampleId" onClose={() => setState({ open: false })}>
14
- <div style={{ padding: 'var(--spacing-sizing-04)' }}>Hello, I am a ({props.placement}) dialog!</div>
15
+ <div style={{ padding: 'var(--spacing-sizing-04)' }}>
16
+ <Flex
17
+ align="center"
18
+ justify="space-between"
19
+ style={{
20
+ width: '100%',
21
+ marginBottom: 'var(--spacing-sizing-04)',
22
+ }}
23
+ >
24
+ <h4>Dialog</h4>
25
+ <Button
26
+ icon={<SvgClose />}
27
+ iconOnly
28
+ label="Close dialog"
29
+ onClick={() => setState({ open: false })}
30
+ variant="tertiary"
31
+ />
32
+ </Flex>
33
+ <p>Hello, I am a ({props.placement}) dialog!</p>
34
+ </div>
15
35
  </Component>
16
36
  </>
17
37
  );
18
38
  },
19
39
  variants: false,
20
- presets,
40
+ sections: [
41
+ {
42
+ title: 'Contained Dialog',
43
+ location: 'beforeDemo',
44
+ content: function ContainedDialog() {
45
+ const [open, setOpen] = useState(false);
46
+
47
+ const container = useRef<HTMLDivElement | undefined>(undefined);
48
+
49
+ return (
50
+ <div
51
+ ref={(node) => (container.current = node || undefined)}
52
+ style={{
53
+ border: '1px solid var(--stroke-neutral-base)',
54
+ padding: 'var(--spacing-sizing-04)',
55
+ minHeight: 200,
56
+ position: 'relative',
57
+ overflow: 'hidden',
58
+ }}
59
+ >
60
+ <Button label="Open Dialog" onClick={() => setOpen(true)} />
61
+ <Dialog
62
+ container={container.current}
63
+ onClose={() => setOpen(false)}
64
+ open={open}
65
+ placement="right"
66
+ >
67
+ <div style={{ padding: 'var(--spacing-sizing-04)' }}>
68
+ <Flex
69
+ align="center"
70
+ justify="space-between"
71
+ style={{
72
+ marginBottom: 'var(--spacing-sizing-04)',
73
+ }}
74
+ >
75
+ <h4>Contained</h4>
76
+ <Button
77
+ icon={<SvgClose />}
78
+ iconOnly
79
+ label="Close dialog"
80
+ onClick={() => setOpen(false)}
81
+ variant="tertiary"
82
+ />
83
+ </Flex>
84
+ <p>Hello, I am a contained dialog!</p>
85
+ </div>
86
+ </Dialog>
87
+ </div>
88
+ );
89
+ },
90
+ },
91
+ ],
92
+ };
93
+
94
+ // eslint-disable-next-line react/no-multi-comp
95
+ export const Usage = () => {
96
+ const [open, setOpen] = useState(false);
97
+
98
+ return (
99
+ <>
100
+ <Button label="Open Dialog" onClick={() => setOpen(true)} />
101
+ <Dialog onClose={() => setOpen(false)} open={open}>
102
+ <div style={{ padding: 'var(--spacing-sizing-04)' }}>
103
+ <Flex align="center" justify="space-between">
104
+ <h1>Dialog Title</h1>
105
+ <Button
106
+ icon={<SvgClose />}
107
+ iconOnly
108
+ label="Close dialog"
109
+ onClick={() => setOpen(false)}
110
+ variant="tertiary"
111
+ />
112
+ </Flex>
113
+ <p>This is the content of the dialog.</p>
114
+ <Button label="Cancel" onClick={() => setOpen(false)} variant="secondary" />
115
+ </div>
116
+ </Dialog>
117
+ </>
118
+ );
21
119
  };