@pure-ds/storybook 0.4.22 → 0.4.24
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/pds-reference.json +3 -3
- package/package.json +2 -2
- package/public/assets/js/app.js +59 -11
- package/public/assets/js/pds.js +60 -12
- package/public/assets/pds/components/pds-drawer.js +1 -1
- package/public/assets/pds/components/pds-form.js +29 -8
- package/src/js/pds-core/pds-config.js +1 -2
- package/src/js/pds-core/pds-generator.js +46 -5
- package/src/js/pds.js +21 -4
- package/stories/GettingStarted.md +27 -3
- package/stories/components/PdsDrawer.stories.js +2 -4
- package/stories/components/PdsForm.stories.js +4902 -4676
- package/stories/components/PdsFormUiSchema.md +1 -1
- package/stories/enhancements/RequiredFields.stories.js +3 -1
- package/stories/enhancements/Toggles.stories.js +30 -0
|
@@ -304,7 +304,7 @@ class PdsDrawer extends HTMLElement {
|
|
|
304
304
|
width: 100%; max-width: 100%;
|
|
305
305
|
margin: 0;
|
|
306
306
|
border-radius: var(--drawer-radius, var(--radius-lg));
|
|
307
|
-
overflow:
|
|
307
|
+
overflow: visible; contain: layout style; will-change: transform;
|
|
308
308
|
touch-action: none;
|
|
309
309
|
outline: none;
|
|
310
310
|
}
|
|
@@ -11,7 +11,7 @@ function getStep(value) {
|
|
|
11
11
|
// Default options for pds-form
|
|
12
12
|
const DEFAULT_OPTIONS = {
|
|
13
13
|
widgets: {
|
|
14
|
-
booleans: "toggle", // 'toggle' | 'checkbox'
|
|
14
|
+
booleans: "toggle", // 'toggle' | 'toggle-with-icons' | 'checkbox'
|
|
15
15
|
numbers: "input", // 'input' | 'range'
|
|
16
16
|
selects: "standard", // 'standard' | 'dropdown'
|
|
17
17
|
},
|
|
@@ -669,10 +669,9 @@ export class SchemaForm extends LitElement {
|
|
|
669
669
|
return useRange ? "input-range" : "input-number";
|
|
670
670
|
}
|
|
671
671
|
if (schema.type === "boolean") {
|
|
672
|
-
//
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
return useToggle ? "toggle" : "checkbox";
|
|
672
|
+
// Return the actual boolean widget type
|
|
673
|
+
const booleanWidget = this.#getOption("widgets.booleans", "toggle");
|
|
674
|
+
return booleanWidget === "checkbox" ? "checkbox" : booleanWidget;
|
|
676
675
|
}
|
|
677
676
|
return "input-text";
|
|
678
677
|
}
|
|
@@ -1489,14 +1488,20 @@ export class SchemaForm extends LitElement {
|
|
|
1489
1488
|
this.#emit("pw:after-render-field", { path, schema: node.schema })
|
|
1490
1489
|
);
|
|
1491
1490
|
|
|
1492
|
-
// Add data-toggle for toggle switches
|
|
1493
|
-
const isToggle = node.widgetKey === "toggle";
|
|
1491
|
+
// Add data-toggle for toggle switches (both toggle and toggle-with-icons)
|
|
1492
|
+
const isToggle = node.widgetKey === "toggle" || node.widgetKey === "toggle-with-icons";
|
|
1493
|
+
const useIconToggle = node.widgetKey === "toggle-with-icons";
|
|
1494
1494
|
|
|
1495
1495
|
// Add range-output class for range inputs if enabled
|
|
1496
1496
|
const isRange = node.widgetKey === "input-range";
|
|
1497
1497
|
const useRangeOutput =
|
|
1498
1498
|
isRange && this.#getOption("enhancements.rangeOutput", true);
|
|
1499
|
-
|
|
1499
|
+
|
|
1500
|
+
// Build class list for label
|
|
1501
|
+
const labelClasses = [];
|
|
1502
|
+
if (useRangeOutput) labelClasses.push("range-output");
|
|
1503
|
+
if (useIconToggle) labelClasses.push("with-icons");
|
|
1504
|
+
const labelClass = labelClasses.length > 0 ? labelClasses.join(" ") : undefined;
|
|
1500
1505
|
|
|
1501
1506
|
const renderControlAndLabel = (isToggle) => {
|
|
1502
1507
|
if (isToggle) return html`${controlTpl} <span data-label>${label}</span>`;
|
|
@@ -1855,6 +1860,22 @@ export class SchemaForm extends LitElement {
|
|
|
1855
1860
|
`
|
|
1856
1861
|
);
|
|
1857
1862
|
|
|
1863
|
+
// Toggle switch with icons (same as toggle, styling comes from .with-icons class on label)
|
|
1864
|
+
this.defineRenderer(
|
|
1865
|
+
"toggle-with-icons",
|
|
1866
|
+
({ id, path, value, attrs, set }) => html`
|
|
1867
|
+
<input
|
|
1868
|
+
id=${id}
|
|
1869
|
+
name=${path}
|
|
1870
|
+
type="checkbox"
|
|
1871
|
+
.checked=${!!value}
|
|
1872
|
+
?disabled=${!!attrs.disabled}
|
|
1873
|
+
?required=${!!attrs.required}
|
|
1874
|
+
@change=${(e) => set(!!e.target.checked)}
|
|
1875
|
+
/>
|
|
1876
|
+
`
|
|
1877
|
+
);
|
|
1878
|
+
|
|
1858
1879
|
this.defineRenderer(
|
|
1859
1880
|
"select",
|
|
1860
1881
|
({ id, path, value, attrs, set, schema, ui, host }) => {
|
|
@@ -737,7 +737,6 @@ export const presets = {
|
|
|
737
737
|
"Data-dense business intelligence app interface with organized hierarchy and professional polish",
|
|
738
738
|
options: {
|
|
739
739
|
liquidGlassEffects: false,
|
|
740
|
-
backgroundMesh: 2,
|
|
741
740
|
},
|
|
742
741
|
colors: {
|
|
743
742
|
primary: "#0066cc", // corporate blue for primary actions
|
|
@@ -815,7 +814,7 @@ presets.default = {
|
|
|
815
814
|
form: {
|
|
816
815
|
options: {
|
|
817
816
|
widgets: {
|
|
818
|
-
booleans: "toggle", // 'toggle' | 'checkbox'
|
|
817
|
+
booleans: "toggle", // 'toggle' | 'toggle-with-icons' | 'checkbox'
|
|
819
818
|
numbers: "input", // 'input' | 'range'
|
|
820
819
|
selects: "standard", // 'standard' | 'dropdown'
|
|
821
820
|
},
|
|
@@ -1923,6 +1923,12 @@ label {
|
|
|
1923
1923
|
line-height: var(--font-line-height-relaxed);
|
|
1924
1924
|
}
|
|
1925
1925
|
|
|
1926
|
+
input, textarea, select {
|
|
1927
|
+
&:focus {
|
|
1928
|
+
outline: none;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1926
1932
|
input, textarea, select {
|
|
1927
1933
|
width: 100%;
|
|
1928
1934
|
min-height: ${minInputHeight}px;
|
|
@@ -1940,11 +1946,7 @@ input, textarea, select {
|
|
|
1940
1946
|
-webkit-appearance: none;
|
|
1941
1947
|
|
|
1942
1948
|
&:focus {
|
|
1943
|
-
outline: none;
|
|
1944
1949
|
border-color: var(--color-primary-500);
|
|
1945
|
-
box-shadow: 0 0 0 ${focusWidth}px color-mix(in oklab, var(--color-primary-500) ${Math.round(
|
|
1946
|
-
(focusRingOpacity || 0.3) * 100
|
|
1947
|
-
)}%, transparent);
|
|
1948
1950
|
background-color: var(--color-surface-base);
|
|
1949
1951
|
}
|
|
1950
1952
|
|
|
@@ -2324,6 +2326,25 @@ label[data-toggle] {
|
|
|
2324
2326
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
2325
2327
|
}
|
|
2326
2328
|
|
|
2329
|
+
/* Icons in toggle knob (opt-in via .with-icons class) */
|
|
2330
|
+
&.with-icons .toggle-knob::before {
|
|
2331
|
+
content: "✕";
|
|
2332
|
+
position: absolute;
|
|
2333
|
+
inset: 0;
|
|
2334
|
+
display: flex;
|
|
2335
|
+
align-items: center;
|
|
2336
|
+
justify-content: center;
|
|
2337
|
+
font-size: 12px;
|
|
2338
|
+
font-weight: bold;
|
|
2339
|
+
color: var(--color-gray-600);
|
|
2340
|
+
transition: opacity 200ms ease;
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
&.with-icons:has(input[type="checkbox"]:checked) .toggle-knob::before {
|
|
2344
|
+
content: "✓";
|
|
2345
|
+
color: var(--color-primary-600);
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2327
2348
|
/* Toggle switch when checked - using :has() selector */
|
|
2328
2349
|
&:has(input[type="checkbox"]:checked) .toggle-switch {
|
|
2329
2350
|
background-color: var(--color-primary-fill);
|
|
@@ -2887,15 +2908,28 @@ tbody {
|
|
|
2887
2908
|
cursor: pointer;
|
|
2888
2909
|
padding: var(--spacing-3) var(--spacing-4);
|
|
2889
2910
|
list-style: none;
|
|
2890
|
-
outline: none;
|
|
2891
2911
|
display: flex;
|
|
2892
2912
|
align-items: center;
|
|
2893
2913
|
gap: var(--spacing-2);
|
|
2914
|
+
border-radius: var(--radius-sm);
|
|
2915
|
+
transition: background-color var(--transition-fast), box-shadow var(--transition-fast);
|
|
2894
2916
|
|
|
2895
2917
|
&::-webkit-details-marker {
|
|
2896
2918
|
display: none;
|
|
2897
2919
|
}
|
|
2898
2920
|
|
|
2921
|
+
&:hover {
|
|
2922
|
+
background-color: var(--color-surface-subtle);
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
&:focus {
|
|
2926
|
+
outline: none;
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
&:focus-visible {
|
|
2930
|
+
box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-primary-500) 30%, transparent);
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2899
2933
|
/* Chevron indicator */
|
|
2900
2934
|
&::after {
|
|
2901
2935
|
content: "";
|
|
@@ -3628,6 +3662,13 @@ nav[data-dropdown] {
|
|
|
3628
3662
|
white-space: nowrap;
|
|
3629
3663
|
}
|
|
3630
3664
|
|
|
3665
|
+
/* Required Legend Utility */
|
|
3666
|
+
:where(.required-legend) {
|
|
3667
|
+
display: block;
|
|
3668
|
+
margin: var(--spacing-3) 0;
|
|
3669
|
+
color: var(--color-text-muted);
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3631
3672
|
/* Max-width utilities */
|
|
3632
3673
|
.max-w-sm { max-width: 400px; } .max-w-md { max-width: 600px; } .max-w-lg { max-width: 800px; } .max-w-xl { max-width: 1200px; }
|
|
3633
3674
|
|
package/src/js/pds.js
CHANGED
|
@@ -961,10 +961,27 @@ async function __setupAutoDefinerAndEnhancers(options) {
|
|
|
961
961
|
enhancers: mergedEnhancers,
|
|
962
962
|
onError: (tag, err) => {
|
|
963
963
|
if (typeof tag === "string" && tag.startsWith("pds-")) {
|
|
964
|
-
//
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
)
|
|
964
|
+
// Check if this is a Lit-dependent component with missing #pds/lit import map
|
|
965
|
+
const litDependentComponents = ['pds-form', 'pds-drawer'];
|
|
966
|
+
const isLitComponent = litDependentComponents.includes(tag);
|
|
967
|
+
const isMissingLitError = err?.message?.includes('#pds/lit') ||
|
|
968
|
+
err?.message?.includes('Failed to resolve module specifier');
|
|
969
|
+
|
|
970
|
+
if (isLitComponent && isMissingLitError) {
|
|
971
|
+
console.error(
|
|
972
|
+
`❌ PDS component <${tag}> requires Lit but #pds/lit is not in import map.\n` +
|
|
973
|
+
`Add this to your HTML <head>:\n` +
|
|
974
|
+
`<script type="importmap">\n` +
|
|
975
|
+
` { "imports": { "#pds/lit": "./path/to/lit.js" } }\n` +
|
|
976
|
+
`</script>\n` +
|
|
977
|
+
`See: https://github.com/pure-ds/core#lit-components`
|
|
978
|
+
);
|
|
979
|
+
} else {
|
|
980
|
+
// Generic component not found warning
|
|
981
|
+
console.warn(
|
|
982
|
+
`⚠️ PDS component <${tag}> not found. Assets may not be installed.`
|
|
983
|
+
);
|
|
984
|
+
}
|
|
968
985
|
} else {
|
|
969
986
|
console.error(`❌ Auto-define error for <${tag}>:`, err);
|
|
970
987
|
}
|
|
@@ -10,12 +10,26 @@ From zero to hero with PDS.
|
|
|
10
10
|
npm install @pure-ds/core
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
**What happens during install:**
|
|
14
|
+
|
|
15
|
+
PDS automatically sets up your project:
|
|
16
|
+
- ✅ Creates `pds.config.js` with commented examples (if it doesn't exist)
|
|
17
|
+
- ✅ Exports static assets to your web root (components, icons, styles)
|
|
18
|
+
- ✅ Copies AI/Copilot instructions to `.github/copilot-instructions.md`
|
|
19
|
+
- ✅ Adds helper scripts to your `package.json` (`pds:export`, `pds:build-icons`)
|
|
20
|
+
|
|
21
|
+
The generated `pds.config.js` includes:
|
|
14
22
|
|
|
15
23
|
```javascript
|
|
24
|
+
// pds.config.js (auto-generated)
|
|
16
25
|
export const config = {
|
|
17
26
|
mode: "live",
|
|
18
|
-
preset: "default"
|
|
27
|
+
preset: "default",
|
|
28
|
+
|
|
29
|
+
// Uncomment and customize as needed:
|
|
30
|
+
// design: { colors: { primary: '#007acc' } },
|
|
31
|
+
// enhancers: [ /* custom enhancements */ ],
|
|
32
|
+
// autoDefine: { predefine: ['pds-icon'] }
|
|
19
33
|
}
|
|
20
34
|
```
|
|
21
35
|
|
|
@@ -23,11 +37,21 @@ Then initialize in your app:
|
|
|
23
37
|
|
|
24
38
|
```javascript
|
|
25
39
|
import { PDS } from '@pure-ds/core';
|
|
26
|
-
import { config } from "
|
|
40
|
+
import { config } from "./pds.config.js"; // project root
|
|
27
41
|
|
|
28
42
|
await PDS.start(config); // That's it! Start writing semantic HTML.
|
|
29
43
|
```
|
|
30
44
|
|
|
45
|
+
**Manual config generation:**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Create or regenerate config with examples
|
|
49
|
+
npx pds-init-config
|
|
50
|
+
|
|
51
|
+
# Force overwrite existing config
|
|
52
|
+
npx pds-init-config --force
|
|
53
|
+
```
|
|
54
|
+
|
|
31
55
|
### Option B: CDN (Zero Install)
|
|
32
56
|
|
|
33
57
|
Perfect for quick prototypes and learning:
|
|
@@ -190,9 +190,7 @@ export const AllPositions = () => {
|
|
|
190
190
|
<pds-drawer id="drawer-right" position="right">
|
|
191
191
|
<div slot="drawer-header" class="flex items-center justify-between">
|
|
192
192
|
<h2>Filter & Sort</h2>
|
|
193
|
-
|
|
194
|
-
<pds-icon icon="x" label="Close"></pds-icon>
|
|
195
|
-
</button>
|
|
193
|
+
|
|
196
194
|
</div>
|
|
197
195
|
<div slot="drawer-content" class="stack-md">
|
|
198
196
|
<p>
|
|
@@ -320,7 +318,7 @@ export const AllPositions = () => {
|
|
|
320
318
|
|
|
321
319
|
<pds-drawer id="drawer-bottom" position="bottom">
|
|
322
320
|
<div slot="drawer-header" class="flex items-center gap-md">
|
|
323
|
-
<pds-icon icon="
|
|
321
|
+
<pds-icon icon="gear" size="lg"></pds-icon>
|
|
324
322
|
<h2>Quick Actions</h2>
|
|
325
323
|
</div>
|
|
326
324
|
<div slot="drawer-content" class="stack-md">
|