@pure-ds/core 0.4.23 → 0.4.25

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.
@@ -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
- // Check if toggle should be used
673
- const useToggle =
674
- this.#getOption("widgets.booleans", "toggle") === "toggle";
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
- const labelClass = useRangeOutput ? "range-output" : undefined;
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 }) => {
package/readme.md CHANGED
@@ -246,10 +246,18 @@ Auto-defined when used. Lazy-loaded via dynamic imports. Styled by your tokens.
246
246
  npm install @pure-ds/core
247
247
  ```
248
248
 
249
- Assets (components, icons) are auto-copied to your project during install. To manually sync:
249
+ **Post-install automation:**
250
+
251
+ During installation, PDS automatically:
252
+ - Creates a default `pds.config.js` (if one doesn't exist)
253
+ - Copies Copilot/AI instructions to `.github/copilot-instructions.md`
254
+ - Adds `pds:export` and `pds:build-icons` scripts to your `package.json`
255
+ - Runs `pds:export` to generate static assets
256
+
257
+ To manually re-sync assets:
250
258
 
251
259
  ```bash
252
- node node_modules/@pure-ds/core/packages/pds-cli/bin/postinstall.js
260
+ npm run pds:export
253
261
  ```
254
262
 
255
263
  ### Lit Import Convention
@@ -1560,6 +1568,27 @@ await PDS.start({ design: myPreset });
1560
1568
  | `npm run pds:css-data` | Generate CSS IntelliSense (tokens, classes, attributes) |
1561
1569
  | `npm run pds:build-icons` | Build custom icon sprite |
1562
1570
  | `npm run sync-assets` | Sync assets between locations |
1571
+ | `npx pds-init-config` | Create default `pds.config.js` with helpful examples |
1572
+
1573
+ ### Initialize Configuration
1574
+
1575
+ Create a starter `pds.config.js` file with commented examples:
1576
+
1577
+ ```bash
1578
+ # Create config in current directory
1579
+ npx pds-init-config
1580
+
1581
+ # Force overwrite existing config
1582
+ npx pds-init-config --force
1583
+ ```
1584
+
1585
+ This generates a `pds.config.js` with:
1586
+ - Basic `mode` and `preset` settings
1587
+ - Commented examples for design token overrides
1588
+ - Template for custom progressive enhancers
1589
+ - Template for lazy-loaded component configuration
1590
+
1591
+ **Note:** During `npm install`, PDS automatically creates this file if it doesn't exist.
1563
1592
 
1564
1593
  ### Export Static Assets
1565
1594
 
@@ -1859,10 +1888,61 @@ export default {
1859
1888
  ### Components Not Loading
1860
1889
 
1861
1890
  1. Verify components directory exists
1862
- 2. Check import map for `#pds/lit`
1891
+ 2. Check import map for `#pds/lit` (required for Lit components - see below)
1863
1892
  3. Manually sync: `node node_modules/pure-ds/packages/pds-cli/bin/postinstall.js`
1864
1893
  4. Check browser console for errors
1865
1894
 
1895
+ ### Lit Components Not Working
1896
+
1897
+ **Symptoms:** `<pds-form>` or other Lit-based components fail to load with module resolution errors.
1898
+
1899
+ **Components requiring Lit:**
1900
+ - `<pds-form>` - JSON Schema forms
1901
+ - `<pds-drawer>` - Drawer/sidebar panels
1902
+
1903
+ **Solution:** Add import map to your HTML `<head>`:
1904
+
1905
+ ```html
1906
+ <script type="importmap">
1907
+ {
1908
+ "imports": {
1909
+ "#pds/lit": "/assets/js/lit.js"
1910
+ }
1911
+ }
1912
+ </script>
1913
+ ```
1914
+
1915
+ Or in bundlers (Vite, Webpack, etc.):
1916
+
1917
+ ```javascript
1918
+ // vite.config.js
1919
+ export default {
1920
+ resolve: {
1921
+ alias: { '#pds/lit': 'lit' }
1922
+ }
1923
+ };
1924
+
1925
+ // webpack.config.js
1926
+ module.exports = {
1927
+ resolve: {
1928
+ alias: { '#pds/lit': 'lit' }
1929
+ }
1930
+ };
1931
+ ```
1932
+
1933
+ **Note:** Wait for components to load before accessing their APIs:
1934
+
1935
+ ```javascript
1936
+ // ❌ Don't do this
1937
+ const form = document.querySelector('pds-form');
1938
+ form.getFormData(); // May fail if component not loaded yet
1939
+
1940
+ // ✅ Do this instead
1941
+ await customElements.whenDefined('pds-form');
1942
+ const form = document.querySelector('pds-form');
1943
+ form.getFormData(); // Safe
1944
+ ```
1945
+
1866
1946
  ### Flash of Unstyled Content
1867
1947
 
1868
1948
  ```javascript
@@ -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
  },
package/src/js/pds.d.ts CHANGED
@@ -154,6 +154,68 @@ export class PDS extends EventTarget {
154
154
  static validateDesign: (designConfig: any, options?: { minContrast?: number }) => { ok: boolean; issues: Array<{ path: string; message: string; ratio: number; min: number; context?: string }> };
155
155
  static validateDesigns: (designs: Array<any> | Record<string, any>, options?: { minContrast?: number }) => { ok: boolean; results: Array<{ name?: string; ok: boolean; issues: Array<{ path: string; message: string; ratio: number; min: number; context?: string }> }> };
156
156
 
157
+ /**
158
+ * Display a toast notification.
159
+ *
160
+ * Automatically ensures the pds-toaster component exists and is loaded before displaying.
161
+ *
162
+ * @param message - The message to display
163
+ * @param options - Toast configuration
164
+ * @param options.type - Toast type/severity ("information" | "success" | "warning" | "error")
165
+ * @param options.duration - Duration in milliseconds (auto-calculated if not provided)
166
+ * @param options.closable - Whether toast can be manually closed (default: true)
167
+ * @param options.persistent - If true, toast won't auto-dismiss (default: false)
168
+ * @returns Toast ID (can be used to dismiss programmatically)
169
+ *
170
+ * @example
171
+ * await PDS.toast('Changes saved!', { type: 'success' });
172
+ *
173
+ * @example
174
+ * await PDS.toast('Error occurred', { type: 'error', persistent: true });
175
+ */
176
+ static toast(
177
+ message: string,
178
+ options?: {
179
+ type?: 'information' | 'success' | 'warning' | 'error';
180
+ duration?: number;
181
+ closable?: boolean;
182
+ persistent?: boolean;
183
+ }
184
+ ): Promise<string>;
185
+
186
+ /**
187
+ * Display a success toast (convenience method).
188
+ *
189
+ * @param message - The success message
190
+ * @param options - Additional toast options (type is preset to 'success')
191
+ * @returns Toast ID
192
+ *
193
+ * @example
194
+ * await PDS.toast.success('Profile updated!');
195
+ */
196
+ static toast: {
197
+ (message: string, options?: { type?: 'information' | 'success' | 'warning' | 'error'; duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
198
+ success(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
199
+ error(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
200
+ warning(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
201
+ info(message: string, options?: { duration?: number; closable?: boolean; persistent?: boolean }): Promise<string>;
202
+ };
203
+
204
+ /**
205
+ * Display a modal dialog for user input or confirmation.
206
+ *
207
+ * @param message - The message or prompt to display
208
+ * @param options - Dialog configuration
209
+ * @returns User's response (string for prompt, boolean for confirm, true for alert)
210
+ *
211
+ * @example
212
+ * const confirmed = await PDS.ask('Delete this item?', { type: 'confirm' });
213
+ *
214
+ * @example
215
+ * const name = await PDS.ask('Enter your name:', { type: 'prompt' });
216
+ */
217
+ static ask(message: string, options?: any): Promise<any>;
218
+
157
219
  /**
158
220
  * Current configuration after PDS.start() completes - read-only, frozen after initialization.
159
221
  * Contains the complete configuration used to initialize PDS, including mode, design, preset, and theme.
package/src/js/pds.js CHANGED
@@ -56,6 +56,7 @@ import { findComponentForElement } from "./pds-core/pds-ontology.js";
56
56
  import { presets, defaultLog } from "./pds-core/pds-config.js";
57
57
  import { enums } from "./pds-core/pds-enums.js";
58
58
  import { ask } from "./common/ask.js";
59
+ import { toast } from "./common/toast.js";
59
60
  import { PDSQuery } from "./pds-core/pds-query.js";
60
61
  import * as common from "./common/common.js";
61
62
  import { defaultPDSEnhancers } from "./pds-core/pds-enhancers.js";
@@ -87,6 +88,7 @@ PDS.isLiveMode = () => registry.isLive;
87
88
  PDS.enums = enums;
88
89
 
89
90
  PDS.ask = ask;
91
+ PDS.toast = toast;
90
92
 
91
93
  // Expose common utilities (deepMerge, isObject, etc.)
92
94
  PDS.common = common;
@@ -961,10 +963,27 @@ async function __setupAutoDefinerAndEnhancers(options) {
961
963
  enhancers: mergedEnhancers,
962
964
  onError: (tag, err) => {
963
965
  if (typeof tag === "string" && tag.startsWith("pds-")) {
964
- // No config available in this context, using console
965
- console.warn(
966
- `⚠️ PDS component <${tag}> not found. Assets may not be installed.`
967
- );
966
+ // Check if this is a Lit-dependent component with missing #pds/lit import map
967
+ const litDependentComponents = ['pds-form', 'pds-drawer'];
968
+ const isLitComponent = litDependentComponents.includes(tag);
969
+ const isMissingLitError = err?.message?.includes('#pds/lit') ||
970
+ err?.message?.includes('Failed to resolve module specifier');
971
+
972
+ if (isLitComponent && isMissingLitError) {
973
+ console.error(
974
+ `❌ PDS component <${tag}> requires Lit but #pds/lit is not in import map.\n` +
975
+ `Add this to your HTML <head>:\n` +
976
+ `<script type="importmap">\n` +
977
+ ` { "imports": { "#pds/lit": "./path/to/lit.js" } }\n` +
978
+ `</script>\n` +
979
+ `See: https://github.com/pure-ds/core#lit-components`
980
+ );
981
+ } else {
982
+ // Generic component not found warning
983
+ console.warn(
984
+ `⚠️ PDS component <${tag}> not found. Assets may not be installed.`
985
+ );
986
+ }
968
987
  } else {
969
988
  console.error(`❌ Auto-define error for <${tag}>:`, err);
970
989
  }